juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [juneau] branch master updated: Improvements to Surrogate support.
Date Thu, 25 Jan 2018 16:11:37 GMT
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 <jamesbognar@apache.org>
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&lt;Normal,MySurrogate&gt;
{
- * 		<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&lt;NormalClass,MySurrogate&gt;
{
+ * 		<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&lt;?&gt;
hint) <jk>throws</jk> ParseException {
- * 			<jk>return</jk> MySurrogate.<jsm>toNormal</jsm>(s);
+ * 		<jk>public</jk> NormalClass unswap(MySurrogate o, ClassMeta&lt;?&gt;
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
&gt; 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
jamesbognar@apache.org.

Mime
View raw message