You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/06/02 00:00:31 UTC

[2/3] incubator-juneau git commit: Improvements to @Query/@FormData/@Header/@Path remoteable annotations.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html b/juneau-core/src/main/javadoc/overview.html
index a4e6885..ef06af5 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6231,7 +6231,9 @@
 	<ja>@BeanProperty</ja>(<js>"foo"</js>)
 				</p>
 			<li>Fixed a race condition in ClassMeta.
-			
+			<li><jsf>URLENC_paramFormat</jsf> has been moved to {@link org.apache.juneau.uon.UonSerializerContext#UON_paramFormat}, 
+				and the UON/URL-Encoding serializers will now always serialize all values as plain text.
+				<br>This means that arrays and maps are converted to simple comma-delimited lists.
 		</ul>
 
 		<h6 class='topic'>org.apache.juneau.rest</h6>
@@ -6463,11 +6465,11 @@
 				<br><ja>@Remoteable</ja> annotation has been moved to this package.
 			<li>Updated doc: <a class='doclink' href='#Remoteable'>6 - Remoteable Services</a>
 			<li>New doc: <a class='doclink' href='#Remoteable.3rdParty'>6.1 -  Interface proxies against 3rd-party REST interfaces</a>
-			<li>New URL-encoding serializer setting: {@link org.apache.juneau.urlencoding.UrlEncodingSerializerContext#URLENC_paramFormat}
+			<li>New URL-encoding serializer setting: <code><del>UrlEncodingSerializerContext.URLENC_paramFormat</del></code>.
 			<li>New methods on {@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder}:
 			<ul>
 				<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder#paramFormat(String) paramFormat(String)}	
-				<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder#plainTextParams() plainTextParams()}	
+				<li><code><del>UrlEncodingSerializerBuilder.plainTextParams()</del></code>	
 			</ul> 		
 		</ul>
 		
@@ -6626,7 +6628,7 @@
 				<ul>
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#executorService(ExecutorService,boolean) executorService(ExecutorService,boolean)}
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#paramFormat(String) paramFormat(ExecutorService,boolean)}
-					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#plainTextParams() plainTextParams()}
+					<li><code><del>RestClientBuilder.plainTextParams()</del></code>
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#noTrace() noTrace()} - Adds a <code>No-Trace: true</code> header on all requests to prevent
 						the servlet from logging errors.
 						<br>Useful for testing scenarios when you don't want the console to end up showing errors done on purpose.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index 769e5eb..9be6df6 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -28,6 +28,7 @@ import org.apache.http.client.config.*;
 import org.apache.http.client.entity.*;
 import org.apache.http.client.methods.*;
 import org.apache.http.client.utils.*;
+import org.apache.http.entity.*;
 import org.apache.http.impl.client.*;
 import org.apache.http.util.*;
 import org.apache.juneau.*;
@@ -37,6 +38,7 @@ import org.apache.juneau.internal.ObjectUtils;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -191,16 +193,22 @@ public final class RestCall {
 				uriBuilder.addParameter(name, partSerializer.serialize(PartType.QUERY, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				query(p.getName(), p.getValue(), skipIfEmpty, partSerializer);
-		} else if (value instanceof String) {
-			String s = value.toString();
-			if (! isEmpty(s))
-				uriBuilder.setCustomQuery(s);
+				query(p.getName(), p.getValue(), skipIfEmpty, UrlEncodingSerializer.DEFAULT_PLAINTEXT);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				query(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
-		} else if (isBean(value)){
+		} else if (isBean(value)) {
 			return query(name, toBeanMap(value), skipIfEmpty, partSerializer);
+		} else if (value instanceof Reader) {
+			try {
+				uriBuilder.setCustomQuery(IOUtils.read(value));
+			} catch (IOException e) {
+				throw new RestCallException(e);
+			}
+		} else if (value instanceof CharSequence) {
+			String s = value.toString();
+			if (! isEmpty(s))
+				uriBuilder.setCustomQuery(s);
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to query(name,value,skipIfEmpty) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
@@ -291,13 +299,21 @@ public final class RestCall {
 				formData.add(new SerializedNameValuePair(name, value, partSerializer));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				if (! (isEmpty(p.getValue()) && skipIfEmpty))
+				if (p.getValue() != null && ! (isEmpty(p.getValue()) && skipIfEmpty))
 					formData.add(p);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				formData(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
 		} else if (isBean(value)) {
 			return formData(name, toBeanMap(value), skipIfEmpty, partSerializer);
+		} else if (value instanceof Reader) {
+			contentType("application/x-www-form-urlencoded");
+			input(value);
+		} else if (value instanceof CharSequence) {
+			try {
+				contentType("application/x-www-form-urlencoded");
+				input(new StringEntity(value.toString()));
+			} catch (UnsupportedEncodingException e) {}
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to formData(name,value,skipIfEmpty) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
@@ -389,13 +405,13 @@ public final class RestCall {
 			uriBuilder.setPath(newPath);
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				path(p.getName(), p.getValue());
+				path(p.getName(), p.getValue(), partSerializer);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				path(p.getKey(), p.getValue());
+				path(p.getKey(), p.getValue(), partSerializer);
 		} else if (isBean(value)) {
-			return path(name, toBeanMap(value));
-		} else {
+			return path(name, toBeanMap(value), partSerializer);
+		} else if (value != null) {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to path(name,value) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
 		return this;
@@ -454,6 +470,7 @@ public final class RestCall {
 	public RestCall input(final Object input) throws RestCallException {
 		this.input = input;
 		this.hasInput = true;
+		this.formData = null;
 		return this;
 	}
 
@@ -508,7 +525,7 @@ public final class RestCall {
 				request.setHeader(name, partSerializer.serialize(PartType.HEADER, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				header(p.getName(), p.getValue(), skipIfEmpty, partSerializer);
+				header(p.getName(), p.getValue(), skipIfEmpty, UrlEncodingSerializer.DEFAULT_PLAINTEXT);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				header(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 8f26768..910a9fb 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -567,39 +567,42 @@ public class RestClient extends CoreObject {
 							if (rmm.getRequestBeanArgs().length > 0) {
 								BeanSession bs = getBeanContext().createSession();
 
-								for (Integer i : rmm.getRequestBeanArgs()) {
-									BeanMap<?> bm = bs.toBeanMap(args[i]);
-									for (BeanPropertyValue bpv : bm.getValues(true)) {
+								for (RemoteMethodArg rma : rmm.getRequestBeanArgs()) {
+									BeanMap<?> bm = bs.toBeanMap(args[rma.index]);
+
+									for (BeanPropertyValue bpv : bm.getValues(false)) {
 										BeanPropertyMeta pMeta = bpv.getMeta();
 										Object val = bpv.getValue();
 
 										Path p = pMeta.getAnnotation(Path.class);
 										if (p != null)
-											rc.path(getName(p.value(), pMeta), val, getPartSerializer(p.serializer()));
+											rc.path(getName(p.name(), p.value(), pMeta), val, getPartSerializer(p.serializer(), rma.serializer));
 
-										Query q1 = pMeta.getAnnotation(Query.class);
-										if (q1 != null)
-											rc.query(getName(q1.value(), pMeta), val, false, getPartSerializer(q1.serializer()));
+										if (val != null) {
+											Query q1 = pMeta.getAnnotation(Query.class);
+											if (q1 != null)
+												rc.query(getName(q1.name(), q1.value(), pMeta), val, q1.skipIfEmpty(), getPartSerializer(q1.serializer(), rma.serializer));
 
-										QueryIfNE q2 = pMeta.getAnnotation(QueryIfNE.class);
-										if (q2 != null)
-											rc.query(getName(q2.value(), pMeta), val, true, getPartSerializer(q2.serializer()));
+											QueryIfNE q2 = pMeta.getAnnotation(QueryIfNE.class);
+											if (q2 != null)
+												rc.query(getName(q2.name(), q2.value(), pMeta), val, true, getPartSerializer(q2.serializer(), rma.serializer));
 
-										FormData f1 = pMeta.getAnnotation(FormData.class);
-										if (f1 != null)
-											rc.formData(getName(f1.value(), pMeta), val, false, getPartSerializer(f1.serializer()));
+											FormData f1 = pMeta.getAnnotation(FormData.class);
+											if (f1 != null)
+												rc.formData(getName(f1.name(), f1.value(), pMeta), val, f1.skipIfEmpty(), getPartSerializer(f1.serializer(), rma.serializer));
 
-										FormDataIfNE f2 = pMeta.getAnnotation(FormDataIfNE.class);
-										if (f2 != null)
-											rc.formData(getName(f2.value(), pMeta), val, true, getPartSerializer(f2.serializer()));
+											FormDataIfNE f2 = pMeta.getAnnotation(FormDataIfNE.class);
+											if (f2 != null)
+												rc.formData(getName(f2.name(), f2.value(), pMeta), val, true, getPartSerializer(f2.serializer(), rma.serializer));
 
-										org.apache.juneau.remoteable.Header h1 = pMeta.getAnnotation(org.apache.juneau.remoteable.Header.class);
-										if (h1 != null)
-											rc.header(getName(h1.value(), pMeta), val, false, getPartSerializer(h1.serializer()));
+											org.apache.juneau.remoteable.Header h1 = pMeta.getAnnotation(org.apache.juneau.remoteable.Header.class);
+											if (h1 != null)
+												rc.header(getName(h1.name(), h1.value(), pMeta), val, h1.skipIfEmpty(), getPartSerializer(h1.serializer(), rma.serializer));
 
-										HeaderIfNE h2 = pMeta.getAnnotation(HeaderIfNE.class);
-										if (h2 != null)
-											rc.header(getName(h2.value(), pMeta), val, true, getPartSerializer(h2.serializer()));
+											HeaderIfNE h2 = pMeta.getAnnotation(HeaderIfNE.class);
+											if (h2 != null)
+												rc.header(getName(h2.name(), h2.value(), pMeta), val, true, getPartSerializer(h2.serializer(), rma.serializer));
+										}
 									}
 								}
 							}
@@ -628,14 +631,20 @@ public class RestClient extends CoreObject {
 		}
 	}
 
-	private static String getName(String name, BeanPropertyMeta pMeta) {
-		if ("*".equals(name) && ! pMeta.getClassMeta().isMapOrBean())
-			name = pMeta.getName();
-		return name;
+	private static String getName(String name1, String name2, BeanPropertyMeta pMeta) {
+		String n = name1.isEmpty() ? name2 : name1;
+		ClassMeta<?> cm = pMeta.getClassMeta();
+		if (n.isEmpty() && (cm.isMapOrBean() || cm.isReader() || cm.isInstanceOf(NameValuePairs.class)))
+			n = "*";
+		if (n.isEmpty())
+			n = pMeta.getName();
+		return n;
 	}
 
-	private static PartSerializer getPartSerializer(Class c) {
-		if (c == UrlEncodingSerializer.class)
+	private static PartSerializer getPartSerializer(Class c, PartSerializer c2) {
+		if (c2 != null)
+			return c2;
+		if (c == PartSerializer.class)
 			return null;
 		PartSerializer pf = partSerializerCache.get(c);
 		if (pf == null) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 463920a..65b4dc8 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -46,6 +46,7 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 
 /**
@@ -1101,7 +1102,7 @@ public class RestClientBuilder extends CoreObjectBuilder {
 	}
 
 	/**
-	 * Sets the {@link UrlEncodingSerializerContext#URLENC_paramFormat} property on the URL-encoding serializers in this group.
+	 * Sets the {@link UonSerializerContext#UON_paramFormat} property on the URL-encoding serializers in this group.
 	 * <p>
 	 * This overrides the behavior of the URL-encoding serializer to quote and escape characters
 	 * in query names and values that may be confused for UON notation (e.g. <js>"'(foo=123)'"</js>, <js>"'@(1,2,3)'"</js>).
@@ -1109,20 +1110,34 @@ public class RestClientBuilder extends CoreObjectBuilder {
 	 *
 	 * @param value The new value for this property.
 	 * @return This object (for method chaining).
-	 * @see UrlEncodingSerializerContext#URLENC_paramFormat
+	 * @see UonSerializerContext#UON_paramFormat
 	 */
 	public RestClientBuilder paramFormat(String value) {
-		super.property(UrlEncodingSerializerContext.URLENC_paramFormat, value);
+		super.property(UonSerializerContext.UON_paramFormat, value);
 		return this;
 	}
 
 	/**
 	 * Shortcut for calling <code>paramFormat(<js>"PLAINTEXT"</js>)</code>.
+	 * <p>
+	 * The default behavior is to serialize part values (query parameters, form data, headers, path variables) in UON notation.
+	 * Calling this method forces plain-text to be used instead.
+	 * <p>
+	 * Specifially, UON notation has the following effects:
+	 * <ul>
+	 * 	<li>Boolean strings (<js>"true"</js>/<js>"false"</js>) and numeric values (<js>"123"</js>) will be
+	 * 			quoted (<js>"'true'"</js>, <js>"'false'"</js>, <js>"'123'"</js>.
+	 * 		<br>This allows them to be differentiated from actual boolean and numeric values.
+	 * 	<li>String such as <js>"(foo='bar')"</js> that mimic UON structures will be quoted and escaped to
+	 * 		<js>"'(foo=bar~'baz~')'"</js>.
+	 * </ul>
+	 * <p>
+	 * The downside to using plain text part serialization is that you cannot serialize arbitrary POJOs.
 	 *
 	 * @return This object (for method chaining).
 	 */
-	public RestClientBuilder plainTextParams() {
-		super.property(UrlEncodingSerializerContext.URLENC_paramFormat, "PLAINTEXT");
+	public RestClientBuilder plainTextParts() {
+		super.property(UonSerializerContext.UON_paramFormat, "PLAINTEXT");
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
new file mode 100644
index 0000000..eed0679
--- /dev/null
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
@@ -0,0 +1,50 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.test;
+
+
+import java.io.*;
+
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Validates the functionality of <ja>@RequestBeans</ja>.
+ */
+@RestResource(
+	path="/testRequestBeanProxy"
+)
+@SuppressWarnings("serial")
+public class RequestBeanProxyResource extends ResourceJena {
+
+	@RestMethod(name="GET", path="/echoQuery")
+	public Reader echoQuery(RestRequest req) throws Exception {
+		return new StringReader(req.getQuery().toString(true));
+	}
+
+	@RestMethod(name="POST", path="/echoFormData")
+	public Reader echoFormData(RestRequest req) throws Exception {
+		return new StringReader(req.getFormData().toString(true));
+	}
+
+	@RestMethod(name="GET", path="/echoHeaders")
+	public Reader echoHeaders(RestRequest req) throws Exception {
+		return new StringReader(req.getHeaders().subset("a,b,c,d,e,f,g,h,i,a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4").toString(true));
+	}
+
+	@RestMethod(name="GET", path="/echoPath/*")
+	public Reader echoPath(RestRequest req) throws Exception {
+		return new StringReader(req.getPathMatch().getRemainder());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
index f04181b..3bee867 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
@@ -60,6 +60,7 @@ import org.apache.juneau.rest.labels.*;
 		PathVariablesResource.class,
 		PropertiesResource.class,
 		QueryResource.class,
+		RequestBeanProxyResource.class,
 		RestClient2Resource.class,
 		SerializersResource.class,
 		StaticFilesResource.class,

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
index 9aeff98..d0f1874 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
@@ -68,7 +68,7 @@ public class FormDataTest extends RestTestcase {
 	//====================================================================================================
 	@Test
 	public void testPlainTextParams() throws Exception {
-		RestClient c = TestMicroservice.client(UrlEncodingSerializer.class, UrlEncodingParser.class).plainTextParams().build();
+		RestClient c = TestMicroservice.client(UrlEncodingSerializer.class, UrlEncodingParser.class).plainTextParts().build();
 		String r;
 
 		Map<String,Object> m = new AMap<String,Object>()