This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new ddab448 Improvements to Surrogate support.
ddab448 is described below
commit ddab44836c278142f86814479bb468bd4719d4f0
Author: JamesBognar <[email protected]>
AuthorDate: Thu Jan 25 11:11:36 2018 -0500
Improvements to Surrogate support.
---
.../a/rttests/RoundTripTransformBeansTest.java | 75 ++++++++++---
.../src/main/java/org/apache/juneau/ClassMeta.java | 7 +-
.../java/org/apache/juneau/annotation/Bean.java | 8 ++
.../org/apache/juneau/transform/Surrogate.java | 122 +++++++--------------
.../org/apache/juneau/transform/SurrogateSwap.java | 24 ++--
juneau-doc/src/main/javadoc/overview.html | 16 ++-
6 files changed, 131 insertions(+), 121 deletions(-)
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
index de001f4..372db4a 100755
---
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripTransformBeansTest.java
@@ -323,7 +323,6 @@ public class RoundTripTransformBeansTest extends
RoundTripTest {
public int f3;
}
-
//====================================================================================================
// Surrogate transforms
//====================================================================================================
@@ -334,41 +333,83 @@ public class RoundTripTransformBeansTest extends
RoundTripTest {
JsonSerializer s =
JsonSerializer.create().ssq().pojoSwaps(D2.class).build();
JsonParser p = JsonParser.create().pojoSwaps(D2.class).build();
Object r;
- D1 d1 = D1.create();
+ D1 x = D1.create();
- r = s.serialize(d1);
+ r = s.serialize(x);
assertEquals("{f2:'f1'}", r);
- d1 = p.parse(r, D1.class);
- assertEquals("f1", d1.f1);
+ x = p.parse(r, D1.class);
+ assertEquals("f1", x.f1);
- r = getSerializer().serialize(d1);
+ r = getSerializer().serialize(x);
assertTrue(TestUtils.toString(r).contains("f2"));
- d1 = roundTrip(d1, D1.class);
+ x = roundTrip(x, D1.class);
}
public static class D1 {
public String f1;
public static D1 create() {
- D1 d1 = new D1();
- d1.f1 = "f1";
- return d1;
+ D1 x = new D1();
+ x.f1 = "f1";
+ return x;
}
}
public static class D2 implements Surrogate {
public String f2;
- public D2(D1 d1) {
- f2 = d1.f1;
+ public D2(D1 x) {
+ f2 = x.f1;
+ }
+ public D2() {}
+ public D1 create() {
+ D1 x = new D1();
+ x.f1 = this.f2;
+ return x;
}
- public D2() {
+ }
+
+ @Test
+ public void testSurrogatesThroughAnnotation() throws Exception {
+ JsonSerializer s = JsonSerializer.DEFAULT_LAX;
+ JsonParser p = JsonParser.DEFAULT;
+ Object r;
+ E1 x = E1.create();
+
+ r = s.serialize(x);
+ assertEquals("{f2:'f1'}", r);
+
+ x = p.parse(r, E1.class);
+ assertEquals("f1", x.f1);
+
+ r = getSerializer().serialize(x);
+ assertTrue(TestUtils.toString(r).contains("f2"));
+
+ x = roundTrip(x, E1.class);
+ }
+
+ @Swap(E2.class)
+ public static class E1 {
+ public String f1;
+
+ public static E1 create() {
+ E1 x = new E1();
+ x.f1 = "f1";
+ return x;
+ }
+ }
+
+ public static class E2 implements Surrogate {
+ public String f2;
+ public E2(E1 x) {
+ f2 = x.f1;
}
- public static D1 valueOf(D2 d2) {
- D1 d1 = new D1();
- d1.f1 = d2.f2;
- return d1;
+ public E2() {}
+ public E1 create() {
+ E1 x = new E1();
+ x.f1 = this.f2;
+ return x;
}
}
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index be3a2d2..bf53232 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -692,8 +692,11 @@ public final class ClassMeta<T> implements Type {
return ps;
}
- if (isParentClass(SurrogateSwap.class, c))
- throw new FormattedRuntimeException("TODO -
Surrogate classes currently not supported in @Swap annotation", c);
+ if (isParentClass(Surrogate.class, c)) {
+ List<SurrogateSwap<?,?>> l =
SurrogateSwap.findPojoSwaps(c);
+ if (! l.isEmpty())
+ return
(PojoSwap<T,?>)l.iterator().next();
+ }
throw new FormattedRuntimeException("Invalid swap class
''{0}'' specified. Must extend from PojoSwap or Surrogate.", c);
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
index 13faf8a..6f1d1af 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/annotation/Bean.java
@@ -110,6 +110,14 @@ public @interface Bean {
* The order specified is the same order that the entries will be
returned by the {@link BeanMap#entrySet()} and
* related methods.
*
+ * <p>
+ * This value is entirely optional if you simply want to expose all the
getters and public fields on
+ * a class as bean properties.
+ * <br>However, it's useful if you want certain getters to be ignored
or you want the properties to be
+ * serialized in a particular order.
+ * <br>Note that on IBM JREs, the property order is the same as the
order in the source code,
+ * whereas on Oracle JREs, the order is entirely random.
+ *
* <h5 class='section'>Example:</h5>
* <p class='bcode'>
* <jc>// Address class with only street/city/state properties (in
that order).</jc>
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/Surrogate.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/Surrogate.java
index cda9667..c5998fb 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/Surrogate.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/Surrogate.java
@@ -13,122 +13,76 @@
package org.apache.juneau.transform;
import org.apache.juneau.*;
+import org.apache.juneau.annotation.*;
/**
* Identifies a class as being a surrogate class.
*
* <p>
* Surrogate classes are used in place of other classes during serialization.
- * For example, you may want to use a surrogate class to change the names or
order of bean properties on a bean.
+ * <br>For example, you may want to use a surrogate class to change the names
or order of bean properties on a bean.
*
* <p>
* This interface has no methods to implement.
- * It's simply used by the framework to identify the class as a surrogate
class when specified as a swap.
+ * <br>It's simply used by the framework to identify the class as a surrogate
class when specified as a swap.
*
* <p>
* The following is an example of a surrogate class change changes a property
name:
* <p class='bcode'>
* <jk>public class</jk> MySurrogate <jk>implements</jk> Surrogate {
- * <jk>public</jk> String surrogateField; <jc>// New bean
property</jc>
*
- * <jk>public</jk> MySurrogate(NormalClass normalClass) {
- * <jk>this</jk>.surrogateField = normalClass.normalField;
- * }
- * }
- * </p>
- *
- * <p>
- * Optionally, a public static method can be used to un-transform a class
during parsing:
- * <p class='bcode'>
- * <jk>public class</jk> MySurrogate <jk>implements</jk> Surrogate {
- * ...
- * <jk>public static</jk> NormalClass
<jsm>toNormalClass</jsm>(SurrogateClass surrogateClass) {
- * <jk>return new</jk>
NormalClass(surrogateClass.transformedField);
- * }
+ * <jc>// Public constructor that wraps the normal object during
serialization.</jc>
+ * <jk>public</jk> MySurrogate(NormalClass o) {...}
+ *
+ * <jc>// Public no-arg constructor using during parsing.</jc>
+ * <jc>// Not required if only used during serializing.</jc>
+ * <jk>public</jk> MySurrogate() {...}
+ *
+ * <jc>// Public method that converts surrogate back into normal
object during parsing.</jc>
+ * <jc>// The method name can be anything (e.g. "build", "create",
etc...).</jc>
+ * <jc>// Not required if only used during serializing.</jc>
+ * <jk>public</jk> NormalClass unswap() {...}
* }
* </p>
*
* <p>
- * Surrogate classes must conform to the following:
- * <ul class='spaced-list'>
- * <li>
- * It must have a one or more public constructors that take in a
single parameter whose type is the normal types.
- * (It is possible to define a class as a surrogate for multiple
class types by using multiple constructors with
- * different parameter types).
- * <li>
- * It optionally can have a public static method that takes in a
single parameter whose type is the transformed
- * type and returns an instance of the normal type.
- * This is called the un-transform method.
- * The method can be called anything.
- * <li>
- * If an un-transform method is present, the class must also
contain a no-arg constructor (so that the
- * transformed class can be instantiated by the parser before
being converted into the normal class by the
- * un-transform method).
- * </ul>
- *
- * <p>
* Surrogate classes are associated with serializers and parsers using the
{@link BeanContextBuilder#pojoSwaps(Class...)}
* method.
* <p class='bcode'>
- * <ja>@Test</ja>
- * <jk>public void</jk> test() <jk>throws</jk> Exception {
- * JsonSerializer s =
JsonSerializer.<jsm>create</jsm>().simple().pojoSwaps(MySurrogate.<jk>class</jk>).build();
- * JsonParser p =
JsonParser.<jsm>create</jsm>().pojoSwaps(MySurrogate.<jk>class</jk>).build();
- * String r;
- * Normal n = Normal.<jsm>create</jsm>();
- *
- * r = s.serialize(n);
- * assertEquals(<js>"{f2:'f1'}"</js>, r);
- *
- * n = p.parse(r, Normal.<jk>class</jk>);
- * assertEquals(<js>"f1"</js>, n.f1);
- * }
- *
- * <jc>// The normal class</jc>
- * <jk>public class</jk> Normal {
- * <jk>public</jk> String f1;
- *
- * <jk>public static</jk> Normal <jsm>create</jsm>() {
- * Normal n = <jk>new</jk> Normal();
- * n.f1 = <js>"f1"</js>;
- * <jk>return</jk> n;
- * }
- * }
- *
- * <jc>// The surrogate class</jc>
- * <jk>public class</jk> MySurrogate <jk>implements</jk> Surrogate {
- * <jk>public</jk> String f2;
- *
- * <jc>// Surrogate constructor</jc>
- * <jk>public</jk> MySurrogate(Normal n) {
- * f2 = n.f1;
- * }
- *
- * <jc>// Constructor used during parsing (only needed if
un-transform method specified)</jc>
- * <jk>public</jk> MySurrogate() {}
+ * JsonSerializer s = JsonSerializer
+ * .<jsm>create</jsm>()
+ * .pojoSwaps(MySurrogate.<jk>class</jk>)
+ * .build();
+ *
+ * JsonParser p = JsonParser
+ * .<jsm>create</jsm>()
+ * .pojoSwaps(MySurrogate.<jk>class</jk>)
+ * .build();
+ * </p>
*
- * <jc>// Un-transform method (optional)</jc>
- * <jk>public static</jk> Normal <jsm>toNormal</jsm>(Surrogate f) {
- * Normal n = <jk>new</jk> Normal();
- * n.f1 = f.f2;
- * <jk>return</jk> n;
- * }
- * }
+ * Surrogates can also be associated using the {@link Swap @Swap} annotation.
+ * <p class='bcode'>
+ * <ja>@Swap</ja>(MySurrogate.<jk>class</jk>)
+ * <jk>public class</jk> NormalClass {...}
* </p>
*
* <p>
- * It should be noted that a surrogate class is functionally equivalent to the
following {@link PojoSwap}
+ * On a side note, a surrogate class is functionally equivalent to the
following {@link PojoSwap}
* implementation:
* <p class='bcode'>
- * <jk>public static class</jk> MySurrogate <jk>extends</jk>
PojoSwap<Normal,MySurrogate> {
- * <jk>public</jk> MySurrogate swap(Normal n) <jk>throws</jk>
SerializeException {
- * <jk>return new</jk> MySurrogate(n);
+ * <jk>public class</jk> MySurrogate <jk>extends</jk>
PojoSwap<NormalClass,MySurrogate> {
+ * <jk>public</jk> MySurrogate swap(NormalClass o) <jk>throws</jk>
SerializeException {
+ * <jk>return new</jk> MySurrogate(o);
* }
- * <jk>public</jk> Normal unswap(MySurrogate s, ClassMeta<?>
hint) <jk>throws</jk> ParseException {
- * <jk>return</jk> MySurrogate.<jsm>toNormal</jsm>(s);
+ * <jk>public</jk> NormalClass unswap(MySurrogate o,
ClassMeta<?> hint) <jk>throws</jk> ParseException {
+ * <jk>return</jk> o.unswap();
* }
* }
* </p>
*
+ * <h5 class='topic'>Documentation</h5>
+ * <ul>
+ * <li><a class="doclink"
href="../../../../overview-summary.html#juneau-marshall.SurrogateClasses">Overview
> SurrogateClasses</a>
+ * </ul>
*/
public interface Surrogate {}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
index 5a0785e..f2e4776 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
@@ -29,19 +29,19 @@ import org.apache.juneau.serializer.*;
public class SurrogateSwap<T,F> extends PojoSwap<T,F> {
private Constructor<F> constructor; // public F(T t);
- private Method untransformMethod; // public static T valueOf(F
f);
+ private Method unswapMethod; // public T build();
/**
* Constructor.
*
* @param forClass The normal class.
* @param constructor The constructor on the surrogate class that takes
the normal class as a parameter.
- * @param untransformMethod The static method that converts surrogate
objects into normal objects.
+ * @param unswapMethod The static method that converts surrogate
objects into normal objects.
*/
- protected SurrogateSwap(Class<T> forClass, Constructor<F> constructor,
Method untransformMethod) {
+ protected SurrogateSwap(Class<T> forClass, Constructor<F> constructor,
Method unswapMethod) {
super(forClass, constructor.getDeclaringClass());
this.constructor = constructor;
- this.untransformMethod = untransformMethod;
+ this.unswapMethod = unswapMethod;
}
/**
@@ -70,14 +70,8 @@ public class SurrogateSwap<T,F> extends PojoSwap<T,F> {
// Find the unswap method if
there is one.
Method unswapMethod = null;
for (Method m : c.getMethods())
{
- if
(pt[0].equals(m.getReturnType())) {
- Class<?>[] mpt
= m.getParameterTypes();
- if (mpt.length
== 1 && mpt[0].equals(c)) { // Only methods with one parameter and where the
return type matches this class.
- int
mod2 = m.getModifiers();
- if
(Modifier.isPublic(mod2) && Modifier.isStatic(mod2)) // Only public static
methods.
-
unswapMethod = m;
- }
- }
+ if
(pt[0].equals(m.getReturnType()) && Modifier.isPublic(m.getModifiers()))
+ unswapMethod = m;
}
l.add(new SurrogateSwap(pt[0],
cc, unswapMethod));
@@ -100,11 +94,11 @@ public class SurrogateSwap<T,F> extends PojoSwap<T,F> {
@Override /* PojoSwap */
@SuppressWarnings("unchecked")
public T unswap(BeanSession session, F f, ClassMeta<?> hint) throws
ParseException {
- if (untransformMethod == null)
- throw new ParseException("static valueOf({0}) method
not implement on surrogate class ''{1}''",
+ if (unswapMethod == null)
+ throw new ParseException("unswap() method not implement
on surrogate class ''{1}''",
f.getClass().getName(),
getNormalClass().getName());
try {
- return (T)untransformMethod.invoke(null, f);
+ return (T)unswapMethod.invoke(f);
} catch (Exception e) {
throw new ParseException(e);
}
diff --git a/juneau-doc/src/main/javadoc/overview.html
b/juneau-doc/src/main/javadoc/overview.html
index b2b577b..c3b1442 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -1810,8 +1810,7 @@
<div class='topic'>
<p>
<p>
- Surrogate classes are very similar in
concept to one-way <code>PojoSwaps</code> except they represent a
- simpler syntax.
+ Surrogate classes are very similar in
concept to <code>PojoSwaps</code> except they're simpler to define.
</p>
<p>
For example, let's say we want to be
able to serialize the following class, but it's not serializable for
@@ -1868,6 +1867,11 @@
When the serializer encounters the
non-serializable class, it will serialize an instance of the surrogate
instead.
</p>
+
+ <h6 class='section'>See Also:</h6>
+ <ul>
+ <li class='jic'>{@link
org.apache.juneau.transform.Surrogate}
+ </ul>
</div>
<!--
=======================================================================================================
-->
@@ -4603,7 +4607,7 @@
<h4 class='topic' onclick='toggle(this)'>3.1.1 - Hello World
Example</h4>
<div class='topic'>
<p>
- A REST resource is simply a Java class
annotated with {@link org.apache.juneau.annotation.RestResource}.
+ A REST resource is simply a Java class
annotated with {@link org.apache.juneau.rest.annotation.RestResource}.
<br>The most common case is a class that
extends {@link org.apache.juneau.rest.RestServlet}, which itself is simply an
extension of {@link
javax.servlet.http.HttpServlet} which allows it to be deployed as a servlet.
</p>
@@ -12549,6 +12553,12 @@
Setter methods that take in
beans and collections of beans can now take in
JSON strings.
</ul>
+ <li>
+ Syntax changed on unswap method on {@link
org.apache.juneau.transform.Surrogate} classes.
+ <br>It's now a regular method instead of a
static method.
+ <li>
+ {@link org.apache.juneau.annotation.Swap @Swap}
annotation can now be used with
+ {@link org.apache.juneau.transform.Surrogate}
classes.
</ul>
<h6 class='topic'>juneau-rest-server</h6>
--
To stop receiving notification emails like this one, please contact
[email protected].