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/03/25 17:25:26 UTC
[1/2] incubator-juneau git commit: Add support for @RestMethod
proxies.
Repository: incubator-juneau
Updated Branches:
refs/heads/master 1174420cf -> 9db2e03fa
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/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 ab660b0..161751a 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
@@ -53,6 +53,7 @@ import org.apache.juneau.utils.*;
* <li><a class="doclink" href="package-summary.html#RestClient">org.apache.juneau.rest.client > REST client API</a> for more information and code examples.
* </ul>
*/
+@SuppressWarnings("hiding")
public final class RestCall {
private final RestClient client; // The client that created this call.
@@ -74,6 +75,9 @@ public final class RestCall {
private TeeOutputStream outputStreams = new TeeOutputStream();
private boolean isClosed = false;
private boolean isFailed = false;
+ private Object input;
+ private Serializer serializer;
+ private Parser parser;
/**
* Constructs a REST call with the specified method name.
@@ -90,6 +94,8 @@ public final class RestCall {
this.retryOn = client.retryOn;
this.retries = client.retries;
this.retryInterval = client.retryInterval;
+ this.serializer = client.serializer;
+ this.parser = client.parser;
}
/**
@@ -107,17 +113,33 @@ public final class RestCall {
* @throws RestCallException If a retry was attempted, but the entity was not repeatable.
*/
public RestCall input(final Object input) throws RestCallException {
+ this.input = input;
+ return this;
+ }
- if (! (request instanceof HttpEntityEnclosingRequestBase))
- throw new RestCallException(0, "Method does not support content entity.", request.getMethod(), request.getURI(), null);
-
- HttpEntity entity = (input instanceof HttpEntity) ? (HttpEntity)input : new RestRequestEntity(input, client.serializer);
-
- ((HttpEntityEnclosingRequestBase)request).setEntity(entity);
-
- if (retries > 1 && ! entity.isRepeatable())
- throw new RestCallException("Rest call set to retryable, but entity is not repeatable.");
+ /**
+ * Specifies the serializer to use on this call.
+ * <p>
+ * Overrides the serializer specified on the {@link RestClient}.
+ *
+ * @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
+ * @return This object (for method chaining).
+ */
+ public RestCall serializer(Serializer serializer) {
+ this.serializer = serializer;
+ return this;
+ }
+ /**
+ * Specifies the parser to use on this call.
+ * <p>
+ * Overrides the parser specified on the {@link RestClient}.
+ *
+ * @param parser The parser used to parse POJOs from the body of the HTTP response.
+ * @return This object (for method chaining).
+ */
+ public RestCall parser(Parser parser) {
+ this.parser = parser;
return this;
}
@@ -520,13 +542,14 @@ public final class RestCall {
* @return This object (for method chaining).
* @throws RestCallException If current entity is not repeatable.
*/
- @SuppressWarnings("hiding")
public RestCall retryable(int retries, long interval, RetryOn retryOn) throws RestCallException {
if (request instanceof HttpEntityEnclosingRequestBase) {
- HttpEntity e = ((HttpEntityEnclosingRequestBase)request).getEntity();
- if (e != null && ! e.isRepeatable())
- throw new RestCallException("Attempt to make call retryable, but entity is not repeatable.");
- }
+ if (input != null && input instanceof HttpEntity) {
+ HttpEntity e = (HttpEntity)input;
+ if (e != null && ! e.isRepeatable())
+ throw new RestCallException("Attempt to make call retryable, but entity is not repeatable.");
+ }
+ }
this.retries = retries;
this.retryInterval = interval;
this.retryOn = (retryOn == null ? RetryOn.DEFAULT : retryOn);
@@ -885,6 +908,16 @@ public final class RestCall {
isConnected = true;
try {
+
+ if (input != null) {
+ if (! (request instanceof HttpEntityEnclosingRequestBase))
+ throw new RestCallException(0, "Method does not support content entity.", request.getMethod(), request.getURI(), null);
+ HttpEntity entity = (input instanceof HttpEntity) ? (HttpEntity)input : new RestRequestEntity(input, getSerializer());
+ ((HttpEntityEnclosingRequestBase)request).setEntity(entity);
+ if (retries > 1 && ! entity.isRepeatable())
+ throw new RestCallException("Rest call set to retryable, but entity is not repeatable.");
+ }
+
int sc = 0;
while (retries > 0) {
retries--;
@@ -1028,9 +1061,9 @@ public final class RestCall {
* @throws RestCallException If no parser was defined on the client.
*/
protected Parser getParser() throws RestCallException {
- if (client.parser == null)
+ if (parser == null)
throw new RestCallException(0, "No parser defined on client", request.getMethod(), request.getURI(), null);
- return client.parser;
+ return parser;
}
/**
@@ -1040,9 +1073,9 @@ public final class RestCall {
* @throws RestCallException If no serializer was defined on the client.
*/
protected Serializer getSerializer() throws RestCallException {
- if (client.serializer == null)
+ if (serializer == null)
throw new RestCallException(0, "No serializer defined on client", request.getMethod(), request.getURI(), null);
- return client.serializer;
+ return serializer;
}
/**
@@ -1114,13 +1147,33 @@ public final class RestCall {
}
/**
- * Converts the output from the connection into an object of the specified class using the registered {@link Parser}.
+ * Same as {@link #getResponse(Type, Type...)} except optimized for a non-parameterized class.
+ * <p>
+ * This is the preferred parse method for simple types since you don't need to cast the results.
+ * <h5 class='section'>Examples:</h5>
+ * <p class='bcode'>
+ * <jc>// Parse into a string.</jc>
+ * String s = restClient.doGet(url).getResponse(String.<jk>class</jk>);
+ *
+ * <jc>// Parse into a bean.</jc>
+ * MyBean b = restClient.doGet(url).getResponse(MyBean.<jk>class</jk>);
*
- * @param type The class to convert the input to.
- * @param <T> The class to convert the input to.
- * @return The parsed output.
+ * <jc>// Parse into a bean array.</jc>
+ * MyBean[] ba = restClient.doGet(url).getResponse(MyBean[].<jk>class</jk>);
+ *
+ * <jc>// Parse into a linked-list of objects.</jc>
+ * List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>);
+ *
+ * <jc>// Parse into a map of object keys/values.</jc>
+ * Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>);
+ * </p>
+ *
+ * @param <T> The class type of the object being created.
+ * See {@link #getResponse(Type, Type...)} for details.
+ * @param type The object type to create.
+ * @return The parsed object.
+ * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
* @throws IOException If a connection error occurred.
- * @throws ParseException If the input contains a syntax error or is malformed for the <code>Content-Type</code> header.
*/
public <T> T getResponse(Class<T> type) throws IOException, ParseException {
BeanContext bc = getParser().getBeanContext();
@@ -1130,28 +1183,48 @@ public final class RestCall {
}
/**
- * Same as {@link #getResponse(Class)}, but useful for parsing into maps and collections of specific types.
+ * Parses HTTP body into the specified object type.
+ * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
+ *
+ * <h5 class='section'>Examples:</h5>
+ * <p class='bcode'>
+ * <jc>// Parse into a linked-list of strings.</jc>
+ * List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+ *
+ * <jc>// Parse into a linked-list of beans.</jc>
+ * List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
*
- * @param type The class to resolve.
- * Can be any of the following:
+ * <jc>// Parse into a linked-list of linked-lists of strings.</jc>
+ * List l = restClient.doGet(url).getResponse(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+ *
+ * <jc>// Parse into a map of string keys/values.</jc>
+ * Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
+ *
+ * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
+ * Map m = restClient.doGet(url).getResponse(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
+ * </p>
+ * <p>
+ * <code>Collection</code> classes are assumed to be followed by zero or one objects indicating the element type.
+ * <p>
+ * <code>Map</code> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
+ * <p>
+ * The array can be arbitrarily long to indicate arbitrarily complex data structures.
+ * <p>
+ * <h5 class='section'>Notes:</h5>
* <ul>
- * <li>{@link ClassMeta}
- * <li>{@link Class}
- * <li>{@link ParameterizedType}
- * <li>{@link GenericArrayType}
+ * <li>Use the {@link #getResponse(Class)} method instead if you don't need a parameterized map/collection.
* </ul>
+ *
+ * @param <T> The class type of the object to create.
+ * @param type The object type to create.
+ * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
* @param args The type arguments of the class if it's a collection or map.
- * Can be any of the following:
- * <ul>
- * <li>{@link ClassMeta}
- * <li>{@link Class}
- * <li>{@link ParameterizedType}
- * <li>{@link GenericArrayType}
- * </ul>
- * @param <T> The class to convert the input to.
- * @return The parsed output.
+ * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
+ * <br>Ignored if the main type is not a map or collection.
+ * @return The parsed object.
+ * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
* @throws IOException If a connection error occurred.
- * @throws ParseException If the input contains a syntax error or is malformed for the <code>Content-Type</code> header.
+ * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections.
*/
@SuppressWarnings("unchecked")
public <T> T getResponse(Type type, Type...args) throws IOException, ParseException {
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/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 9ff546a..6594ced 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
@@ -59,7 +59,6 @@ public class RestClient extends CoreObject {
private final UrlEncodingSerializer urlEncodingSerializer; // Used for form posts only.
final Parser parser;
private final String remoteableServletUri;
- private final Map<Method,String> remoteableServiceUriMap;
private final String rootUrl;
private volatile boolean isClosed = false;
private final StackTraceElement[] creationStack;
@@ -113,7 +112,6 @@ public class RestClient extends CoreObject {
this.headers = Collections.unmodifiableMap(h2);
this.interceptors = interceptors.toArray(new RestCallInterceptor[interceptors.size()]);
this.remoteableServletUri = remoteableServletUri;
- this.remoteableServiceUriMap = new ConcurrentHashMap<Method,String>(remoteableServiceUriMap);
this.rootUrl = rootUri;
this.retryOn = retryOn;
this.retries = retries;
@@ -410,29 +408,65 @@ public class RestClient extends CoreObject {
* @throws RuntimeException If the Remotable service URI has not been specified on this
* client by calling {@link RestClientBuilder#remoteableServletUri(String)}.
*/
- @SuppressWarnings("unchecked")
public <T> T getRemoteableProxy(final Class<T> interfaceClass) {
if (remoteableServletUri == null)
throw new RuntimeException("Remoteable service URI has not been specified.");
- return (T)Proxy.newProxyInstance(
- interfaceClass.getClassLoader(),
- new Class[] { interfaceClass },
- new InvocationHandler() {
- @Override /* InvocationHandler */
- public Object invoke(Object proxy, Method method, Object[] args) {
- try {
- String uri = remoteableServiceUriMap.get(method);
- if (uri == null) {
- // Constructing this string each time can be time consuming, so cache it.
- uri = remoteableServletUri + '/' + interfaceClass.getName() + '/' + ClassUtils.getMethodSignature(method);
- remoteableServiceUriMap.put(method, uri);
+ return getRemoteableProxy(interfaceClass, remoteableServletUri + '/' + interfaceClass.getName());
+ }
+
+ /**
+ * Create a new proxy interface for the specified REST PROXY interface.
+ *
+ * @param interfaceClass The interface to create a proxy for.
+ * @param proxyUrl The URL of the REST method annotated with <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code>.
+ * @return The new proxy interface.
+ */
+ public <T> T getRemoteableProxy(final Class<T> interfaceClass, final Object proxyUrl) {
+ return getRemoteableProxy(interfaceClass, proxyUrl, serializer, parser);
+ }
+
+ /**
+ * Same as {@link #getRemoteableProxy(Class, Object)} but allows you to override the serializer and parser used.
+ *
+ * @param interfaceClass The interface to create a proxy for.
+ * @param proxyUrl The URL of the REST method annotated with <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code>.
+ * @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
+ * @param parser The parser used to parse POJOs from the body of the HTTP response.
+ * @return The new proxy interface.
+ */
+ @SuppressWarnings({ "unchecked", "hiding" })
+ public <T> T getRemoteableProxy(final Class<T> interfaceClass, final Object proxyUrl, final Serializer serializer, final Parser parser) {
+ try {
+ return (T)Proxy.newProxyInstance(
+ interfaceClass.getClassLoader(),
+ new Class[] { interfaceClass },
+ new InvocationHandler() {
+
+ final Map<Method,String> uriCache = new ConcurrentHashMap<Method,String>();
+ final String uri = toURI(proxyUrl).toString();
+
+ @Override /* InvocationHandler */
+ public Object invoke(Object proxy, Method method, Object[] args) {
+
+ // Constructing this string each time can be time consuming, so cache it.
+ String u = uriCache.get(method);
+ if (u == null) {
+ try {
+ u = uri + '/' + URLEncoder.encode(ClassUtils.getMethodSignature(method), "utf-8");
+ } catch (UnsupportedEncodingException e) {}
+ uriCache.put(method, u);
+ }
+
+ try {
+ return doPost(u, args).serializer(serializer).parser(parser).getResponse(method.getGenericReturnType());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
- return doPost(uri, args).getResponse(method.getReturnType());
- } catch (Exception e) {
- throw new RuntimeException(e);
}
- }
- });
+ });
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
private Pattern absUrlPattern = Pattern.compile("^\\w+\\:\\/\\/.*");
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/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 0075437..39a2f88 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
@@ -1015,6 +1015,20 @@ public class RestClientBuilder extends CoreObjectBuilder {
return property(PARSER_fileCharset, value);
}
+ /**
+ * When called, <code>No-Trace: true</code> is added to requests.
+ * <p>
+ * This gives the opportunity for the servlet to not log errors on invalid requests.
+ * This is useful for testing purposes when you don't want your log file to show lots
+ * of errors that are simply the results of testing.
+ *
+ * @return This object (for method chaining).
+ */
+ public RestClientBuilder noTrace() {
+ return header("No-Trace", true);
+ }
+
+
@Override /* CoreObjectBuilder */
public RestClientBuilder beansRequireDefaultConstructor(boolean value) {
super.beansRequireDefaultConstructor(value);
@@ -1342,6 +1356,7 @@ public class RestClientBuilder extends CoreObjectBuilder {
@Override /* CoreObjectBuilder */
public RestClientBuilder debug(boolean value) {
super.debug(value);
+ header("Debug", value);
return this;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/pom.xml
----------------------------------------------------------------------
diff --git a/juneau-rest-test/pom.xml b/juneau-rest-test/pom.xml
index 0b613dd..7e5cbff 100644
--- a/juneau-rest-test/pom.xml
+++ b/juneau-rest-test/pom.xml
@@ -46,6 +46,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxy.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxy.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxy.java
new file mode 100644
index 0000000..6b96290
--- /dev/null
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxy.java
@@ -0,0 +1,62 @@
+// ***************************************************************************************************************************
+// * 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.util.*;
+
+/**
+ * Interface proxy exposed in InterfaceProxyResource and tested in InterfaceProxyTest.
+ */
+public interface InterfaceProxy {
+
+ void returnVoid();
+ int returnInt();
+ Integer returnInteger();
+ float returnFloat();
+ Float returnFloatObject();
+ String returnString();
+ String returnNullString();
+ int[] returnIntArray();
+ String[] returnStringArray();
+ List<Integer> returnIntegerList();
+ List<String> returnStringList();
+ Bean returnBean();
+ Bean[] returnBeanArray();
+ List<Bean> returnBeanList();
+
+ void setNothing();
+ void setInt(int x);
+ void setInteger(Integer x);
+ void setFloat(float x);
+ void setFloatObject(Float x);
+ void setString(String x);
+ void setNullString(String x);
+ void setIntArray(int[] x);
+ void setStringArray(String[] x);
+ void setIntegerList(List<Integer> x);
+ void setStringList(List<String> x);
+ void setBean(Bean x);
+ void setBeanArray(Bean[] x);
+ void setBeanList(List<Bean> x);
+
+ public static class Bean {
+ public int a;
+ public String b;
+
+ Bean init() {
+ this.a = 1;
+ this.b = "foo";
+ return this;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxyResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxyResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxyResource.java
new file mode 100644
index 0000000..82de1c2
--- /dev/null
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InterfaceProxyResource.java
@@ -0,0 +1,128 @@
+// ***************************************************************************************************************************
+// * 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 static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.jena.*;
+import org.junit.*;
+
+/**
+ * Tests inteface proxies exposed through <code>@RestMethod(name="PROXY")</code>
+ */
+@RestResource(
+ path="/testInterfaceProxyResource")
+public class InterfaceProxyResource extends RestServletJenaDefault {
+ private static final long serialVersionUID = 1L;
+
+ //====================================================================================================
+ // Test that Q-values are being resolved correctly.
+ //====================================================================================================
+ @RestMethod(name="PROXY", path="/proxy/*")
+ public InterfaceProxy getProxy() {
+ return new InterfaceProxy() {
+ @Override
+ public void returnVoid() {}
+ @Override
+ public Integer returnInteger() { return 1;}
+ @Override
+ public int returnInt() { return 1; }
+ @Override
+ public float returnFloat() { return 1f; }
+ @Override
+ public Float returnFloatObject() { return 1f; }
+ @Override
+ public String returnString() { return "foobar"; }
+ @Override
+ public String returnNullString() { return null; }
+ @Override
+ public int[] returnIntArray() { return new int[]{1,2}; }
+ @Override
+ public String[] returnStringArray() { return new String[]{"foo","bar",null};}
+ @Override
+ public List<Integer> returnIntegerList() { return Arrays.asList(new Integer[]{1,2}); }
+ @Override
+ public List<String> returnStringList() { return Arrays.asList(new String[]{"foo","bar",null}); }
+ @Override
+ public Bean returnBean() { return new Bean().init(); }
+ @Override
+ public Bean[] returnBeanArray() { return new Bean[]{new Bean().init()}; }
+ @Override
+ public List<Bean> returnBeanList() { return Arrays.asList(new Bean().init()); }
+
+ @Override
+ public void setNothing() {
+ }
+ @Override
+ public void setInt(int x) {
+ assertEquals(1, x);
+ }
+ @Override
+ public void setInteger(Integer x) {
+ assertEquals((Integer)1, x);
+ }
+ @Override
+ public void setFloat(float x) {
+ assertTrue(1f == x);
+ }
+ @Override
+ public void setFloatObject(Float x) {
+ assertTrue(1f == x);
+ }
+ @Override
+ public void setString(String x) {
+ assertEquals("foo", x);
+ }
+ @Override
+ public void setNullString(String x) {
+ assertNull(x);
+ }
+ @Override
+ public void setIntArray(int[] x) {
+ assertObjectEquals("[1,2]", x);
+ }
+ @Override
+ public void setStringArray(String[] x) {
+ assertObjectEquals("['foo','bar',null]", x);
+ }
+ @Override
+ public void setIntegerList(List<Integer> x) {
+ assertObjectEquals("[1,2,null]", x);
+ }
+ @Override
+ public void setStringList(List<String> x) {
+ assertObjectEquals("['foo','bar',null]", x);
+ }
+ @Override
+ public void setBean(Bean x) {
+ assertObjectEquals("{a:1,b:'foo'}", x);
+ }
+ @Override
+ public void setBeanArray(Bean[] x) {
+ assertObjectEquals("[{a:1,b:'foo'}]", x);
+ }
+ @Override
+ public void setBeanList(List<Bean> x) {
+ assertObjectEquals("[{a:1,b:'foo'}]", x);
+ }
+ };
+ }
+
+ private static void assertObjectEquals(String e, Object o) {
+ Assert.assertEquals(e, JsonSerializer.DEFAULT_LAX.toString(o));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/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 f24c34c..ceeaf48 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
@@ -38,6 +38,7 @@ import org.apache.juneau.rest.labels.*;
InheritanceResource.TestParsers.class,
InheritanceResource.TestProperties.class,
InheritanceResource.TestSerializers.class,
+ InterfaceProxyResource.class,
LargePojosResource.class,
MessagesResource.Messages2Resource.class,
MessagesResource.class,
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/InterfaceProxyTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/InterfaceProxyTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/InterfaceProxyTest.java
new file mode 100644
index 0000000..4ed272d
--- /dev/null
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/InterfaceProxyTest.java
@@ -0,0 +1,225 @@
+// ***************************************************************************************************************************
+// * 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 static org.apache.juneau.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.msgpack.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.test.InterfaceProxy.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.uon.*;
+import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.xml.*;
+import org.junit.*;
+import org.junit.runner.*;
+import org.junit.runners.*;
+
+@RunWith(Parameterized.class)
+public class InterfaceProxyTest extends RestTestcase {
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { /* 0 */ "Json", JsonSerializer.DEFAULT, JsonParser.DEFAULT },
+ { /* 1 */ "Xml", XmlSerializer.DEFAULT, XmlParser.DEFAULT },
+ { /* 2 */ "Mixed", JsonSerializer.DEFAULT, XmlParser.DEFAULT },
+ { /* 3 */ "Html", HtmlSerializer.DEFAULT, HtmlParser.DEFAULT },
+ { /* 4 */ "MessagePack", MsgPackSerializer.DEFAULT, MsgPackParser.DEFAULT },
+ { /* 5 */ "UrlEncoding", UrlEncodingSerializer.DEFAULT, UrlEncodingParser.DEFAULT },
+ { /* 6 */ "Uon", UonSerializer.DEFAULT, UonParser.DEFAULT },
+ });
+ }
+
+ private Serializer serializer;
+ private Parser parser;
+
+ public InterfaceProxyTest(String label, Serializer serializer, Parser parser) {
+ this.serializer = serializer;
+ this.parser = parser;
+ }
+
+ private InterfaceProxy getProxy() {
+ return getClient(serializer, parser).getRemoteableProxy(InterfaceProxy.class, "/testInterfaceProxyResource/proxy");
+ }
+
+ @Test
+ public void returnVoid() {
+ getProxy().returnVoid();
+ }
+
+ @Test
+ public void returnInteger() {
+ assertEquals((Integer)1, getProxy().returnInteger());
+ }
+
+ @Test
+ public void returnInt() {
+ assertEquals(1, getProxy().returnInt());
+ }
+
+ @Test
+ public void returnFloat() {
+ assertTrue(1f == getProxy().returnFloat());
+ }
+
+ @Test
+ public void returnFloatObject() {
+ assertTrue(1f == getProxy().returnFloatObject());
+ }
+
+ @Test
+ public void returnString() {
+ assertEquals("foobar", getProxy().returnString());
+ }
+
+ @Test
+ public void returnNullString() {
+ assertNull(getProxy().returnNullString());
+ }
+
+ @Test
+ public void returnIntArray() {
+ assertObjectEquals("[1,2]", getProxy().returnIntArray());
+ }
+
+ @Test
+ public void returnStringArray() {
+ assertObjectEquals("['foo','bar',null]", getProxy().returnStringArray());
+ }
+
+ @Test
+ public void returnIntegerList() {
+ assertObjectEquals("[1,2]", getProxy().returnIntegerList());
+ assertTrue(getProxy().returnIntegerList().get(0) instanceof Integer);
+ }
+
+ @Test
+ public void returnStringList() {
+ assertObjectEquals("['foo','bar',null]", getProxy().returnStringList());
+ assertTrue(getProxy().returnStringList() instanceof List);
+ }
+
+ @Test
+ public void returnBean() {
+ assertObjectEquals("{a:1,b:'foo'}", getProxy().returnBean());
+ assertClass(InterfaceProxy.Bean.class, getProxy().returnBean());
+ }
+
+ @Test
+ public void returnBeanArray() {
+ assertObjectEquals("[{a:1,b:'foo'}]", getProxy().returnBeanArray());
+ assertClass(InterfaceProxy.Bean.class, getProxy().returnBeanArray()[0]);
+ }
+
+ @Test
+ public void returnBeanList() {
+ assertObjectEquals("[{a:1,b:'foo'}]", getProxy().returnBeanList());
+ assertClass(InterfaceProxy.Bean.class, getProxy().returnBeanList().get(0));
+ }
+
+ @Test
+ public void setNothing() {
+ getProxy().setNothing();
+ }
+
+ @Test
+ public void setInt() {
+ getProxy().setInt(1);
+ }
+
+ @Test
+ public void setWrongInt() {
+ try {
+ getProxy().setInt(2);
+ fail("Exception expected");
+ } catch (Exception e) {
+ // Good.
+ }
+ }
+
+ @Test
+ public void setInteger() {
+ getProxy().setInteger(1);
+ }
+
+ @Test
+ public void setFloat() {
+ getProxy().setFloat(1f);
+ }
+
+ @Test
+ public void setFloatObject() {
+ getProxy().setFloatObject(1f);
+ }
+
+ @Test
+ public void setString() {
+ getProxy().setString("foo");
+ }
+
+ @Test
+ public void setNullString() {
+ getProxy().setNullString(null);
+ }
+
+ @Test
+ public void setNullStringBad() {
+ try {
+ getProxy().setNullString("foo");
+ fail("Exception expected");
+ } catch (Exception e) {
+ // Good.
+ }
+ }
+
+ @Test
+ public void setIntArray() {
+ getProxy().setIntArray(new int[]{1,2});
+ }
+
+ @Test
+ public void setStringArray() {
+ getProxy().setStringArray(new String[]{"foo","bar",null});
+ }
+
+ @Test
+ public void setIntegerList() {
+ getProxy().setIntegerList(Arrays.asList(new Integer[]{1,2,null}));
+ }
+
+ @Test
+ public void setStringList() {
+ getProxy().setStringList(Arrays.asList("foo","bar",null));
+ }
+
+ @Test
+ public void setBean() {
+ getProxy().setBean(new Bean().init());
+ }
+
+ @Test
+ public void setBeanArray() {
+ getProxy().setBeanArray(new Bean[]{new Bean().init()});
+ }
+
+ @Test
+ public void setBeanList() {
+ getProxy().setBeanList(Arrays.asList(new Bean().init()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
index 70d4a5d..1a23177 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
@@ -12,6 +12,12 @@
// ***************************************************************************************************************************
package org.apache.juneau.rest.test;
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.serializer.*;
import org.junit.*;
/**
@@ -22,15 +28,33 @@ import org.junit.*;
public class RestTestcase {
private static boolean microserviceStarted;
+ private static List<RestClient> clients = new ArrayList<RestClient>();
@BeforeClass
public static void setUp() {
microserviceStarted = TestMicroservice.startMicroservice();
}
+ /**
+ * Creates a REST client against the test microservice using the specified serializer and parser.
+ * Client is automatically closed on tear-down.
+ */
+ protected RestClient getClient(Serializer serializer, Parser parser) {
+ RestClient rc = TestMicroservice.client(serializer, parser).build();
+ clients.add(rc);
+ return rc;
+ }
+
@AfterClass
public static void tearDown() {
if (microserviceStarted)
TestMicroservice.stopMicroservice();
+ for (RestClient rc : clients) {
+ try {
+ rc.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestMicroservice.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestMicroservice.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestMicroservice.java
index 25a740d..a2f0777 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestMicroservice.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestMicroservice.java
@@ -96,7 +96,7 @@ public class TestMicroservice {
try {
return new RestClientBuilder()
.rootUrl(microserviceURI)
- // .httpClient(createHttpClient(), true)
+ .noTrace()
;
} catch (Exception e) {
throw new RuntimeException(e);
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestUtils.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestUtils.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestUtils.java
index caf9041..102c17e 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestUtils.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/TestUtils.java
@@ -37,6 +37,13 @@ public class TestUtils {
}
/**
+ * Assert that the object is an instance of the specified class.
+ */
+ public static void assertClass(Class<?> c, Object o) {
+ Assert.assertEquals(c, o == null ? null : o.getClass());
+ }
+
+ /**
* Assert that the object equals the specified string after running it through ws.toString().
*/
public static void assertObjectEquals(String s, Object o, WriterSerializer ws) {
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
index 2eb975c..0714aca 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
@@ -36,6 +36,7 @@ import org.junit.runners.Suite.*;
GroupsTest.class,
GzipTest.class,
InheritanceTest.class,
+ InterfaceProxyTest.class,
JacocoDummyTest.class,
LargePojosTest.class,
MessagesTest.class,
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
index 5cfa4e5..2fb2560 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/CallMethod.java
@@ -44,7 +44,7 @@ import org.apache.juneau.urlencoding.*;
* Represents a single Java servlet/resource method annotated with {@link RestMethod @RestMethod}.
*/
@SuppressWarnings("hiding")
-final class CallMethod implements Comparable<CallMethod> {
+class CallMethod implements Comparable<CallMethod> {
private final java.lang.reflect.Method method;
private final String httpMethod;
private final UrlPathPattern pathPattern;
@@ -60,7 +60,7 @@ final class CallMethod implements Comparable<CallMethod> {
private final UrlEncodingSerializer urlEncodingSerializer;
private final ObjectMap properties;
private final Map<String,String> defaultRequestHeaders;
- private final String defaultEncoding;
+ private final String defaultCharset;
private final boolean deprecated;
private final String description, tags, summary, externalDocs;
private final Integer priority;
@@ -86,7 +86,7 @@ final class CallMethod implements Comparable<CallMethod> {
this.urlEncodingSerializer = b.urlEncodingSerializer;
this.properties = b.properties;
this.defaultRequestHeaders = b.defaultRequestHeaders;
- this.defaultEncoding = b.defaultEncoding;
+ this.defaultCharset = b.defaultCharset;
this.deprecated = b.deprecated;
this.description = b.description;
this.tags = b.tags;
@@ -98,7 +98,7 @@ final class CallMethod implements Comparable<CallMethod> {
}
private static class Builder {
- private String httpMethod, defaultEncoding, description, tags, summary, externalDocs;
+ private String httpMethod, defaultCharset, description, tags, summary, externalDocs;
private UrlPathPattern pathPattern;
private CallMethod.MethodParam[] params;
private RestGuard[] guards;
@@ -263,7 +263,7 @@ final class CallMethod implements Comparable<CallMethod> {
defaultRequestHeaders.put(h[0], h[1]);
}
- defaultEncoding = properties.getString(REST_defaultCharset, context.getDefaultCharset());
+ defaultCharset = properties.getString(REST_defaultCharset, context.getDefaultCharset());
String paramFormat = properties.getString(REST_paramFormat, context.getParamFormat());
plainParams = paramFormat.equals("PLAIN");
@@ -808,8 +808,8 @@ final class CallMethod implements Comparable<CallMethod> {
for (int i = 0; i < pathPattern.getVars().length; i++)
req.setPathParameter(pathPattern.getVars()[i], patternVals[i]);
- req.init(method, remainder, createRequestProperties(properties, req), defaultRequestHeaders, defaultEncoding, serializers, parsers, urlEncodingParser, encoders);
- res.init(req.getProperties(), defaultEncoding, serializers, urlEncodingSerializer, encoders);
+ req.init(method, remainder, createRequestProperties(properties, req), defaultRequestHeaders, defaultCharset, serializers, parsers, urlEncodingParser, encoders);
+ res.init(req.getProperties(), defaultCharset, serializers, urlEncodingSerializer, encoders);
// Class-level guards
for (RestGuard guard : context.getGuards())
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
index 29113f4..89abdc4 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -399,14 +399,58 @@ public final class RestContext extends Context {
throw new RestServletException("@RestMethod method {0}.{1} must be defined as public.", this.getClass().getName(), method.getName());
CallMethod sm = new CallMethod(resource, method, this);
- _javaRestMethods.put(method.getName(), sm);
-
String httpMethod = sm.getHttpMethod();
- if (! routers.containsKey(httpMethod))
- routers.put(httpMethod, new CallRouter.Builder(httpMethod));
-
- routers.get(httpMethod).add(sm);
+ // PROXY is a special case where a method returns an interface that we
+ // can perform REST calls against.
+ // We override the CallMethod.invoke() method to insert our logic.
+ if ("PROXY".equals(httpMethod)) {
+
+ final ClassMeta<?> interfaceClass = beanContext.getClassMeta(method.getGenericReturnType());
+ sm = new CallMethod(resource, method, this) {
+
+ @Override
+ int invoke(String pathInfo, RestRequest req, RestResponse res) throws RestException {
+
+ int rc = super.invoke(pathInfo, req, res);
+ if (rc != SC_OK)
+ return rc;
+
+ final Object o = res.getOutput();
+
+ if ("GET".equals(req.getMethod())) {
+ res.setOutput(ClassUtils.getMethodInfo(interfaceClass.getProxyableMethods().values()));
+ return SC_OK;
+
+ } else if ("POST".equals(req.getMethod())) {
+ if (pathInfo.indexOf('/') != -1)
+ pathInfo = pathInfo.substring(pathInfo.lastIndexOf('/')+1);
+ pathInfo = RestUtils.decode(pathInfo);
+ java.lang.reflect.Method m = interfaceClass.getProxyableMethods().get(pathInfo);
+ if (m != null) {
+ try {
+ // Parse the args and invoke the method.
+ Parser p = req.getParser();
+ Object input = p.isReaderParser() ? req.getReader() : req.getInputStream();
+ res.setOutput(m.invoke(o, p.parseArgs(input, m.getGenericParameterTypes())));
+ return SC_OK;
+ } catch (Exception e) {
+ throw new RestException(SC_INTERNAL_SERVER_ERROR, e);
+ }
+ }
+ }
+ return SC_NOT_FOUND;
+ }
+ };
+
+ _javaRestMethods.put(method.getName(), sm);
+ addToRouter(routers, "GET", sm);
+ addToRouter(routers, "POST", sm);
+
+ } else {
+ _javaRestMethods.put(method.getName(), sm);
+ addToRouter(routers, httpMethod, sm);
+ }
} catch (RestServletException e) {
throw new RestServletException("Problem occurred trying to serialize methods on class {0}, methods={1}", this.getClass().getName(), JsonSerializer.DEFAULT_LAX.serialize(methodsFound)).initCause(e);
}
@@ -484,6 +528,12 @@ public final class RestContext extends Context {
}
}
+ private static void addToRouter(Map<String, CallRouter.Builder> routers, String httpMethodName, CallMethod cm) throws RestServletException {
+ if (! routers.containsKey(httpMethodName))
+ routers.put(httpMethodName, new CallRouter.Builder(httpMethodName));
+ routers.get(httpMethodName).add(cm);
+ }
+
private static class Builder {
boolean allowHeaderParams, allowBodyParam, renderResponseStackTraces, useStackTraceHashes;
@@ -1416,5 +1466,4 @@ public final class RestContext extends Context {
throw new RestServletException("Exception occurred while constructing class ''{0}''", c).initCause(e);
}
}
-
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
index 2b55b47..8a13d2f 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestLogger.java
@@ -148,7 +148,8 @@ public abstract class RestLogger {
* <p>
* Subclasses can override this method to provide their own logic for determining when exceptions are logged.
* <p>
- * The default implementation will return <jk>false</jk> if <js>"noTrace=true"</js> is passed in the query string.
+ * The default implementation will return <jk>false</jk> if <js>"noTrace=true"</js> is passed in the query string
+ * or <code>No-Trace: true</code> is specified in the header.
*
* @param req The HTTP request.
* @param res The HTTP response.
@@ -156,6 +157,8 @@ public abstract class RestLogger {
* @return <jk>true</jk> if exception should be logged.
*/
protected boolean shouldLog(HttpServletRequest req, HttpServletResponse res, RestException e) {
+ if ("true".equals(req.getHeader("No-Trace")))
+ return false;
String q = req.getQueryString();
return (q == null ? true : q.indexOf("noTrace=true") == -1);
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
index 98aba93..cd5d42c 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -67,7 +67,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
private final RestContext context;
private final String method;
- private String pathRemainder, body;
+ private String pathRemainder;
+ private byte[] body;
private Method javaMethod;
private ObjectMap properties;
private SerializerGroup serializerGroup;
@@ -118,14 +119,16 @@ public final class RestRequest extends HttpServletRequestWrapper {
method = _method;
if (context.isAllowBodyParam()) {
- body = getQueryParameter("body");
- if (body != null)
+ String b = getQueryParameter("body");
+ if (b != null) {
setHeader("Content-Type", UonSerializer.DEFAULT.getResponseContentType());
+ this.body = b.getBytes(IOUtils.UTF8);
+ }
}
defaultServletHeaders = context.getDefaultRequestHeaders();
- debug = "true".equals(getQueryParameter("debug", "false"));
+ debug = "true".equals(getQueryParameter("debug", "false")) || "true".equals(getHeader("Debug", "false"));
if (debug) {
context.getLogger().log(Level.INFO, toString());
@@ -1216,10 +1219,9 @@ public final class RestRequest extends HttpServletRequestWrapper {
* @throws IOException If a problem occurred trying to read from the reader.
*/
public String getBodyAsString() throws IOException {
- if (body != null)
- return body;
- body = IOUtils.read(getReader()).toString();
- return body;
+ if (body == null)
+ body = IOUtils.readBytes(getInputStream(), 1024);
+ return new String(body, IOUtils.UTF8);
}
/**
@@ -1247,7 +1249,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
*/
protected Reader getUnbufferedReader() throws IOException {
if (body != null)
- return new CharSequenceReader(body);
+ return new CharSequenceReader(new String(body, IOUtils.UTF8));
return new InputStreamReader(getInputStream(), getCharacterEncoding());
}
@@ -1263,21 +1265,15 @@ public final class RestRequest extends HttpServletRequestWrapper {
@Override /* ServletRequest */
public ServletInputStream getInputStream() throws IOException {
+ if (body != null)
+ return new ServletInputStream2(body);
+
Encoder enc = getEncoder();
ServletInputStream is = super.getInputStream();
if (enc != null) {
final InputStream is2 = enc.getInputStream(is);
- return new ServletInputStream() {
- @Override /* InputStream */
- public final int read() throws IOException {
- return is2.read();
- }
- @Override /* InputStream */
- public final void close() throws IOException {
- is2.close();
- }
- };
+ return new ServletInputStream2(is2);
}
return is;
}
@@ -1893,7 +1889,9 @@ public final class RestRequest extends HttpServletRequestWrapper {
for (Map.Entry<String,String> e : defaultServletHeaders.entrySet()) {
sb.append("\t").append(e.getKey()).append(": ").append(e.getValue()).append("\n");
}
- if (method.equals("PUT") || method.equals("POST")) {
+ if (javaMethod == null) {
+ sb.append("***init() not called yet!***\n");
+ } else if (method.equals("PUT") || method.equals("POST")) {
sb.append("---Body---\n");
try {
sb.append(getBodyAsString()).append("\n");
@@ -1985,4 +1983,30 @@ public final class RestRequest extends HttpServletRequestWrapper {
void setJavaMethod(Method method) {
this.javaMethod = method;
}
+
+ /**
+ * ServletInputStream wrapper around a normal input stream.
+ */
+ private static class ServletInputStream2 extends ServletInputStream {
+
+ private final InputStream is;
+
+ private ServletInputStream2(InputStream is) {
+ this.is = is;
+ }
+
+ private ServletInputStream2(byte[] b) {
+ this(new ByteArrayInputStream(b));
+ }
+
+ @Override /* InputStream */
+ public final int read() throws IOException {
+ return is.read();
+ }
+
+ @Override /* InputStream */
+ public final void close() throws IOException {
+ is.close();
+ }
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
index 4856070..4270a38 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
@@ -17,6 +17,7 @@ import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
+import org.apache.juneau.annotation.*;
import org.apache.juneau.encoders.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.rest.*;
@@ -38,13 +39,26 @@ public @interface RestMethod {
* <p>
* Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>.
* <p>
- * Can also be a non-HTTP-standard name that is passed in through a <code>&method=methodName</code> URL parameter.
- * <p>
* Method names are case-insensitive (always folded to upper-case).
* <p>
- * If a method name is not specified, then the method name is determined based on the Java method name.<br>
- * For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected as <js>"POST"</js>.
-
+ * Besides the standard HTTP method names, the following can also be specified:
+ * <ul>
+ * <li><js>"*"</js> - Denotes any method.
+ * <br>Use this if you want to capture any HTTP methods in a single Java method.
+ * <br>The {@link Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used
+ * to distinguish the actual HTTP method name.
+ * <li><js>""</js> - Auto-detect.
+ * <br>The method name is determined based on the Java method name.
+ * <br>For example, if the method is <code>doPost(...)</code>, then the method name is automatically detected as <js>"POST"</js>.
+ * <li><js>"PROXY"</js> - Remote-proxy interface.
+ * <br>This denotes a Java method that returns an object (usually an interface, often annotated with the {@link Remoteable @Remoteable} annotation)
+ * to be used as a remote proxy using <code>RestClient.getRemoteableProxy(Class<T> interfaceClass, String url)</code>.
+ * <br>This allows you to construct client-side interface proxies using REST as a transport medium.
+ * <br>Conceptually, this is simply a fancy <code>POST</code> against the url <js>"/{path}/{javaMethodName}"</js> where the arguments
+ * are marshalled from the client to the server as an HTTP body containing an array of objects,
+ * passed to the method as arguments, and then the resulting object is marshalled back to the client.
+ * <li>Anything else - Overloaded non-HTTP-standard names that are passed in through a <code>&method=methodName</code> URL parameter.
+ * </ul>
*/
String name() default "";
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-rest/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java b/juneau-rest/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
index 15a96ad..c6bc0f4 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
@@ -115,7 +115,7 @@ public abstract class RemoteableServlet extends RestServletDefault {
throw new RestException(SC_NOT_FOUND, "Method not found"); //$NON-NLS-1$
// Parse the args and invoke the method.
- ClassMeta<?>[] argTypes = req.getBeanSession().getClassMetas(m.getParameterTypes());
+ ClassMeta<?>[] argTypes = req.getBeanSession().getClassMetas(m.getGenericParameterTypes());
Object[] params = p.parseArgs(req.getReader(), argTypes);
return m.invoke(service, params);
}
[2/2] incubator-juneau git commit: Add support for @RestMethod
proxies.
Posted by ja...@apache.org.
Add support for @RestMethod proxies.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/9db2e03f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/9db2e03f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/9db2e03f
Branch: refs/heads/master
Commit: 9db2e03fa04ec54e5e2d85f9c4ab530233700853
Parents: 1174420
Author: JamesBognar <ja...@apache.org>
Authored: Sat Mar 25 10:25:20 2017 -0700
Committer: JamesBognar <ja...@apache.org>
Committed: Sat Mar 25 10:25:20 2017 -0700
----------------------------------------------------------------------
.../a/rttests/RoundTripLargeObjectsTest.java | 18 +-
.../ByteArrayBase64SwapComboTest.java | 28 +--
.../transforms/CalendarSwapComboTest.java | 72 +++---
.../juneau/transforms/DateSwapComboTest.java | 72 +++---
.../urlencoding/UrlEncodingSerializerTest.java | 16 +-
.../java/org/apache/juneau/BeanSession.java | 8 +-
.../main/java/org/apache/juneau/ClassMeta.java | 33 ++-
.../java/org/apache/juneau/html/HtmlParser.java | 40 +++-
.../java/org/apache/juneau/html/HtmlTag.java | 10 +-
.../org/apache/juneau/internal/ClassUtils.java | 41 ++++
.../apache/juneau/msgpack/MsgPackParser.java | 25 +++
.../java/org/apache/juneau/parser/Parser.java | 30 ++-
.../juneau/parser/ParserGroupBuilder.java | 12 +
.../serializer/SerializerGroupBuilder.java | 12 +
.../java/org/apache/juneau/uon/UonParser.java | 14 +-
.../juneau/urlencoding/UrlEncodingParser.java | 84 +++++--
.../urlencoding/UrlEncodingSerializer.java | 45 +++-
juneau-core/src/main/javadoc/overview.html | 35 +++
.../examples/addressbook/AddressBook.java | 25 ++-
.../examples/addressbook/IAddressBook.java | 3 +
.../rest/addressbook/AddressBookResource.java | 29 +--
.../examples/rest/AddressBookResourceTest.java | 40 ++++
.../org/apache/juneau/rest/client/RestCall.java | 153 +++++++++----
.../apache/juneau/rest/client/RestClient.java | 74 ++++--
.../juneau/rest/client/RestClientBuilder.java | 15 ++
juneau-rest-test/pom.xml | 1 +
.../apache/juneau/rest/test/InterfaceProxy.java | 62 +++++
.../rest/test/InterfaceProxyResource.java | 128 +++++++++++
.../java/org/apache/juneau/rest/test/Root.java | 1 +
.../juneau/rest/test/InterfaceProxyTest.java | 225 +++++++++++++++++++
.../apache/juneau/rest/test/RestTestcase.java | 24 ++
.../juneau/rest/test/TestMicroservice.java | 2 +-
.../org/apache/juneau/rest/test/TestUtils.java | 7 +
.../org/apache/juneau/rest/test/_TestSuite.java | 1 +
.../java/org/apache/juneau/rest/CallMethod.java | 14 +-
.../org/apache/juneau/rest/RestContext.java | 63 +++++-
.../java/org/apache/juneau/rest/RestLogger.java | 5 +-
.../org/apache/juneau/rest/RestRequest.java | 64 ++++--
.../juneau/rest/annotation/RestMethod.java | 24 +-
.../rest/remoteable/RemoteableServlet.java | 2 +-
40 files changed, 1295 insertions(+), 262 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripLargeObjectsTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripLargeObjectsTest.java b/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripLargeObjectsTest.java
index 4e41a60..139f03c 100755
--- a/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripLargeObjectsTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/a/rttests/RoundTripLargeObjectsTest.java
@@ -50,55 +50,55 @@ public class RoundTripLargeObjectsTest extends RoundTripTest {
{ /* 0 */
"Json DEFAULT",
new JsonSerializerBuilder().trimNullProperties(false),
- JsonParser.DEFAULT,
+ new JsonParserBuilder(),
0
},
{ /* 1 */
"Json DEFAULT_LAX",
new JsonSerializerBuilder().simple().trimNullProperties(false),
- JsonParser.DEFAULT,
+ new JsonParserBuilder(),
0
},
{ /* 2 */
"Json DEFAULT_SQ",
new JsonSerializerBuilder().simple().trimNullProperties(false),
- JsonParser.DEFAULT,
+ new JsonParserBuilder(),
0
},
{ /* 3 */
"Xml DEFAULT w/namespaces,validation",
new XmlSerializerBuilder().sq().ns().trimNullProperties(false).addNamespaceUrisToRoot(true).useWhitespace(true),
- XmlParser.DEFAULT,
+ new XmlParserBuilder(),
CHECK_XML_WHITESPACE | VALIDATE_XML
},
{ /* 4 */
"Xml DEFAULT wo/namespaces,validation",
new XmlSerializerBuilder().sq().trimNullProperties(false),
- XmlParser.DEFAULT,
+ new XmlParserBuilder(),
CHECK_XML_WHITESPACE
},
{ /* 5 */
"Html",
new HtmlSerializerBuilder().trimNullProperties(false),
- HtmlParser.DEFAULT,
+ new HtmlParserBuilder(),
CHECK_XML_WHITESPACE
},
{ /* 6 */
"UrlEncoding",
new UrlEncodingSerializerBuilder().trimNullProperties(false),
- UrlEncodingParser.DEFAULT,
+ new UrlEncodingParserBuilder(),
0
},
{ /* 7 */
"Uon",
new UonSerializerBuilder().trimNullProperties(false),
- UonParser.DEFAULT,
+ new UonParserBuilder(),
0
},
{ /* 8 */
"MsgPack",
new MsgPackSerializerBuilder().trimNullProperties(false),
- MsgPackParser.DEFAULT,
+ new MsgPackParserBuilder(),
0
},
// { /* 9 */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core-test/src/test/java/org/apache/juneau/transforms/ByteArrayBase64SwapComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/transforms/ByteArrayBase64SwapComboTest.java b/juneau-core-test/src/test/java/org/apache/juneau/transforms/ByteArrayBase64SwapComboTest.java
index b9ac9c3..08934de 100644
--- a/juneau-core-test/src/test/java/org/apache/juneau/transforms/ByteArrayBase64SwapComboTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/transforms/ByteArrayBase64SwapComboTest.java
@@ -30,7 +30,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
@Parameterized.Parameters
public static Collection<Object[]> getParameters() {
return Arrays.asList(new Object[][] {
- {
+ { /* 0 */
"ByteArray1d",
new byte[] {1,2,3},
/* Json */ "'AQID'",
@@ -55,7 +55,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>AQID</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>AQID</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 1 */
"ByteArray2d",
new byte[][]{{1,2,3},{4,5,6},null},
/* Json */ "['AQID','BAUG',null]",
@@ -71,16 +71,16 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* Uon */ "@(AQID,BAUG,null)",
/* UonT */ "@(AQID,BAUG,null)",
/* UonR */ "@(\n\tAQID,\n\tBAUG,\n\tnull\n)",
- /* UrlEnc */ "_value=@(AQID,BAUG,null)",
- /* UrlEncT */ "_value=@(AQID,BAUG,null)",
- /* UrlEncR */ "_value=@(\n\tAQID,\n\tBAUG,\n\tnull\n)",
+ /* UrlEnc */ "0=AQID&1=BAUG&2=null",
+ /* UrlEncT */ "0=AQID&1=BAUG&2=null",
+ /* UrlEncR */ "0=AQID\n&1=BAUG\n&2=null",
/* MsgPack */ "93A441514944A442415547C0",
/* MsgPackT */ "93A441514944A442415547C0",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 2 */
"ListOfByteArrays",
new ArrayList<byte[]>(){{
add(new byte[]{1,2,3});
@@ -109,7 +109,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 3 */
"MapOfByteArrays",
new LinkedHashMap<String,byte[]>() {{
put("foo", new byte[]{1,2,3});
@@ -139,7 +139,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>AQID</jp:foo>\n<jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n<jp:_x0000_>BAUG</jp:_x0000_>\n<jp:null>BwgJ</jp:null>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>AQID</jp:foo>\n <jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n <jp:_x0000_>BAUG</jp:_x0000_>\n <jp:null>BwgJ</jp:null>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 4 */
"BeanWithByteArrayField",
new BeanWithByteArrayField().init(),
/* Json */ "{f:'AQID'}",
@@ -164,7 +164,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f>AQID</jp:f>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f>AQID</jp:f>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 5 */
"BeanWithByteArray2dField",
new BeanWithByteArray2dField().init(),
/* Json */ "{f:['AQID','BAUG',null]}",
@@ -189,7 +189,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</jp:f>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n </jp:f>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 6 */
"BeanWithByteArrayNullField",
new BeanWithByteArrayNullField().init(),
/* Json */ "{f:null}",
@@ -214,7 +214,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 7 */
"BeanWithByteArrayListField",
new BeanWithByteArrayListField().init(),
/* Json */ "{f:['AQID','BAUG',null]}",
@@ -239,7 +239,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</jp:f>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n </jp:f>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 8 */
"BeanWithByteArrayMapField",
new BeanWithByteArrayMapField().init(),
/* Json */ "{f:{foo:'AQID',bar:null,null:'BAUG'}}",
@@ -264,7 +264,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f rdf:parseType='Resource'>\n<jp:foo>AQID</jp:foo>\n<jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n<jp:_x0000_>BAUG</jp:_x0000_>\n</jp:f>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f rdf:parseType='Resource'>\n <jp:foo>AQID</jp:foo>\n <jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n <jp:_x0000_>BAUG</jp:_x0000_>\n </jp:f>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 9 */
"BeanWithByteArrayBeanListField",
new BeanWithByteArrayBeanListField().init(),
/* Json */ "{f:[{f1:'AQID',f2:['AQID','BAUG',null],f3:null,f4:['AQID','BAUG',null],f5:{foo:'AQID',bar:null,null:'BAUG'}},null]}",
@@ -289,7 +289,7 @@ public class ByteArrayBase64SwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:f>\n<rdf:Seq>\n<rdf:li rdf:parseType='Resource'>\n<jp:f1>AQID</jp:f1>\n<jp:f2>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</jp:f2>\n<jp:f3 rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n<jp:f4>\n<rdf:Seq>\n<rdf:li>AQID</rdf:li>\n<rdf:li>BAUG</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</jp:f4>\n<jp:f5 rdf:parseType='Resource'>\n<jp:foo>AQID</jp:foo>\n<jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n<jp:_x0000_>BAUG</jp:_x0000_>\n</jp:f5>\n</rdf:li>\n<rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n</rdf:Seq>\n</jp:f>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:f>\n <rdf:Seq>\n <rdf:li rdf:parseType='Resource'>\n <jp:f1>AQID</jp:f1>\n <jp:f2>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n </jp:f2>\n <jp:f3 rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n <jp:f4>\n <rdf:Seq>\n <rdf:li>AQID</rdf:li>\n <rdf:li>BAUG</rdf:li>\n <rdf:li rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n </jp:f4>\n <jp:f5 rdf:parseType='Resource'>\n <jp:foo>AQID</jp:foo>\n <jp:bar rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n <jp:_x0000_>BAUG</jp:_x0000_>\n </jp:f5>\n </rdf:li>\n <rdf:li rdf:r
esource='http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'/>\n </rdf:Seq>\n </jp:f>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 10 */
"BeanWithByteArrayBeanMapField",
new BeanWithByteArrayBeanMapField().init(),
/* Json */ "{f:{foo:{f1:'AQID',f2:['AQID','BAUG',null],f3:null,f4:['AQID','BAUG',null],f5:{foo:'AQID',bar:null,null:'BAUG'}},bar:null,null:{f1:'AQID',f2:['AQID','BAUG',null],f3:null,f4:['AQID','BAUG',null],f5:{foo:'AQID',bar:null,null:'BAUG'}}}}",
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core-test/src/test/java/org/apache/juneau/transforms/CalendarSwapComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/transforms/CalendarSwapComboTest.java b/juneau-core-test/src/test/java/org/apache/juneau/transforms/CalendarSwapComboTest.java
index c3453b3..b804241 100644
--- a/juneau-core-test/src/test/java/org/apache/juneau/transforms/CalendarSwapComboTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/transforms/CalendarSwapComboTest.java
@@ -42,7 +42,7 @@ public class CalendarSwapComboTest extends ComboTest {
@Parameterized.Parameters
public static Collection<Object[]> getParameters() {
return Arrays.asList(new Object[][] {
- {
+ { /* 0 */
"CalendarSwap.ToString/singleDate",
singleDate,
CalendarSwap.ToString.class,
@@ -68,7 +68,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Sun Mar 03 10:11:12 PST 1901</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Sun Mar 03 10:11:12 PST 1901</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 1 */
"CalendarSwap.ToString/dateArray",
dateArray,
CalendarSwap.ToString.class,
@@ -85,16 +85,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@('Sun Mar 03 10:11:12 PST 1901')",
/* UonT */ "@('Sun Mar 03 10:11:12 PST 1901')",
/* UonR */ "@(\n\t'Sun Mar 03 10:11:12 PST 1901'\n)",
- /* UrlEnc */ "_value=@('Sun+Mar+03+10:11:12+PST+1901')",
- /* UrlEncT */ "_value=@('Sun+Mar+03+10:11:12+PST+1901')",
- /* UrlEncR */ "_value=@(\n\t'Sun+Mar+03+10:11:12+PST+1901'\n)",
+ /* UrlEnc */ "0='Sun+Mar+03+10:11:12+PST+1901'",
+ /* UrlEncT */ "0='Sun+Mar+03+10:11:12+PST+1901'",
+ /* UrlEncR */ "0='Sun+Mar+03+10:11:12+PST+1901'",
/* MsgPack */ "91BC53756E204D61722030332031303A31313A3132205053542031393031",
/* MsgPackT */ "91BC53756E204D61722030332031303A31313A3132205053542031393031",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 2 */
"CalendarSwap.ToString",
dateMap,
CalendarSwap.ToString.class,
@@ -120,7 +120,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>Sun Mar 03 10:11:12 PST 1901</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>Sun Mar 03 10:11:12 PST 1901</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 3 */
"CalendarSwap.ISO8601DT/singleDate",
singleDate,
CalendarSwap.ISO8601DT.class,
@@ -146,7 +146,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>1901-03-03T10:11:12-08:00</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>1901-03-03T10:11:12-08:00</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 4 */
"CalendarSwap.ISO8601DT/dateArray",
dateArray,
CalendarSwap.ISO8601DT.class,
@@ -163,16 +163,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@(1901-03-03T10:11:12-08:00)",
/* UonT */ "@(1901-03-03T10:11:12-08:00)",
/* UonR */ "@(\n\t1901-03-03T10:11:12-08:00\n)",
- /* UrlEnc */ "_value=@(1901-03-03T10:11:12-08:00)",
- /* UrlEncT */ "_value=@(1901-03-03T10:11:12-08:00)",
- /* UrlEncR */ "_value=@(\n\t1901-03-03T10:11:12-08:00\n)",
+ /* UrlEnc */ "0=1901-03-03T10:11:12-08:00",
+ /* UrlEncT */ "0=1901-03-03T10:11:12-08:00",
+ /* UrlEncR */ "0=1901-03-03T10:11:12-08:00",
/* MsgPack */ "91B9313930312D30332D30335431303A31313A31322D30383A3030",
/* MsgPackT */ "91B9313930312D30332D30335431303A31313A31322D30383A3030",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 5 */
"CalendarSwap.ISO8601DT/dateMap",
dateMap,
CalendarSwap.ISO8601DT.class,
@@ -198,7 +198,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>1901-03-03T10:11:12-08:00</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>1901-03-03T10:11:12-08:00</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 6 */
"CalendarSwap.RFC2822DTZ/singleDate",
singleDate,
CalendarSwap.RFC2822DTZ.class,
@@ -224,7 +224,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Sun, 03 Mar 1901 18:11:12 GMT</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Sun, 03 Mar 1901 18:11:12 GMT</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 7 */
"CalendarSwap.RFC2822DTZ/dateArray",
dateArray,
CalendarSwap.RFC2822DTZ.class,
@@ -241,16 +241,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@('Sun, 03 Mar 1901 18:11:12 GMT')",
/* UonT */ "@('Sun, 03 Mar 1901 18:11:12 GMT')",
/* UonR */ "@(\n\t'Sun, 03 Mar 1901 18:11:12 GMT'\n)",
- /* UrlEnc */ "_value=@('Sun,+03+Mar+1901+18:11:12+GMT')",
- /* UrlEncT */ "_value=@('Sun,+03+Mar+1901+18:11:12+GMT')",
- /* UrlEncR */ "_value=@(\n\t'Sun,+03+Mar+1901+18:11:12+GMT'\n)",
+ /* UrlEnc */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
+ /* UrlEncT */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
+ /* UrlEncR */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
/* MsgPack */ "91BD53756E2C203033204D617220313930312031383A31313A313220474D54",
/* MsgPackT */ "91BD53756E2C203033204D617220313930312031383A31313A313220474D54",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 8 */
"CalendarSwap.RFC2822DTZ/dateMap",
dateMap,
CalendarSwap.RFC2822DTZ.class,
@@ -276,7 +276,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>Sun, 03 Mar 1901 18:11:12 GMT</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>Sun, 03 Mar 1901 18:11:12 GMT</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 9 */
"CalendarLongSwap",
singleDate,
CalendarLongSwap.class,
@@ -302,7 +302,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>-2172116928000</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>-2172116928000</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 10 */
"CalendarLongSwap/dateArray",
dateArray,
CalendarLongSwap.class,
@@ -319,16 +319,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@(-2172116928000)",
/* UonT */ "@(-2172116928000)",
/* UonR */ "@(\n\t-2172116928000\n)",
- /* UrlEnc */ "_value=@(-2172116928000)",
- /* UrlEncT */ "_value=@(-2172116928000)",
- /* UrlEncR */ "_value=@(\n\t-2172116928000\n)",
+ /* UrlEnc */ "0=-2172116928000",
+ /* UrlEncT */ "0=-2172116928000",
+ /* UrlEncR */ "0=-2172116928000",
/* MsgPack */ "91D3FFFFFE0643BDFA00",
/* MsgPackT */ "91D3FFFFFE0643BDFA00",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>-2172116928000</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>-2172116928000</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>-2172116928000</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 11 */
"CalendarLongSwap/dateMap",
dateMap,
CalendarLongSwap.class,
@@ -354,7 +354,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>-2172116928000</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>-2172116928000</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 12 */
"CalendarMapSwap/singleDate",
singleDate,
CalendarMapSwap.class,
@@ -380,7 +380,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:time>-2172116928000</jp:time>\n<jp:timeZone>PST</jp:timeZone>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:time>-2172116928000</jp:time>\n <jp:timeZone>PST</jp:timeZone>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 13 */
"CalendarMapSwap/dateArray",
dateArray,
CalendarMapSwap.class,
@@ -397,16 +397,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@((time=-2172116928000,timeZone=PST))",
/* UonT */ "@((time=-2172116928000,timeZone=PST))",
/* UonR */ "@(\n\t(\n\t\ttime=-2172116928000,\n\t\ttimeZone=PST\n\t)\n)",
- /* UrlEnc */ "_value=@((time=-2172116928000,timeZone=PST))",
- /* UrlEncT */ "_value=@((time=-2172116928000,timeZone=PST))",
- /* UrlEncR */ "_value=@(\n\t(\n\t\ttime=-2172116928000,\n\t\ttimeZone=PST\n\t)\n)",
+ /* UrlEnc */ "0=(time=-2172116928000,timeZone=PST)",
+ /* UrlEncT */ "0=(time=-2172116928000,timeZone=PST)",
+ /* UrlEncR */ "0=(\n\ttime=-2172116928000,\n\ttimeZone=PST\n)",
/* MsgPack */ "9182A474696D65D3FFFFFE0643BDFA00A874696D655A6F6E65A3505354",
/* MsgPackT */ "9182A474696D65D3FFFFFE0643BDFA00A874696D655A6F6E65A3505354",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n<jp:timeZone>PST</jp:timeZone>\n</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n<jp:timeZone>PST</jp:timeZone>\n</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li rdf:parseType='Resource'>\n <jp:time>-2172116928000</jp:time>\n <jp:timeZone>PST</jp:timeZone>\n </rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 14 */
"CalendarMapSwap/dateMap",
dateMap,
CalendarMapSwap.class,
@@ -432,7 +432,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n<jp:timeZone>PST</jp:timeZone>\n</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo rdf:parseType='Resource'>\n <jp:time>-2172116928000</jp:time>\n <jp:timeZone>PST</jp:timeZone>\n </jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 15 */
"CalendarSwap.DateMedium/singleDate",
singleDate,
CalendarSwap.DateMedium.class,
@@ -458,7 +458,7 @@ public class CalendarSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Mar 3, 1901</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Mar 3, 1901</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 16 */
"CalendarSwap.DateMedium/dateArray",
dateArray,
CalendarSwap.DateMedium.class,
@@ -475,16 +475,16 @@ public class CalendarSwapComboTest extends ComboTest {
/* Uon */ "@('Mar 3, 1901')",
/* UonT */ "@('Mar 3, 1901')",
/* UonR */ "@(\n\t'Mar 3, 1901'\n)",
- /* UrlEnc */ "_value=@('Mar+3,+1901')",
- /* UrlEncT */ "_value=@('Mar+3,+1901')",
- /* UrlEncR */ "_value=@(\n\t'Mar+3,+1901'\n)",
+ /* UrlEnc */ "0='Mar+3,+1901'",
+ /* UrlEncT */ "0='Mar+3,+1901'",
+ /* UrlEncR */ "0='Mar+3,+1901'",
/* MsgPack */ "91AB4D617220332C2031393031",
/* MsgPackT */ "91AB4D617220332C2031393031",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Mar 3, 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Mar 3, 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Mar 3, 1901</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 17 */
"CalendarSwap.DateMedium/dateMap",
dateMap,
CalendarSwap.DateMedium.class,
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core-test/src/test/java/org/apache/juneau/transforms/DateSwapComboTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/transforms/DateSwapComboTest.java b/juneau-core-test/src/test/java/org/apache/juneau/transforms/DateSwapComboTest.java
index 5965e94..376cbec 100644
--- a/juneau-core-test/src/test/java/org/apache/juneau/transforms/DateSwapComboTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/transforms/DateSwapComboTest.java
@@ -38,7 +38,7 @@ public class DateSwapComboTest extends ComboTest {
@Parameterized.Parameters
public static Collection<Object[]> getParameters() {
return Arrays.asList(new Object[][] {
- {
+ { /* 0 */
"DateSwap.ToString/singleDate",
singleDate,
DateSwap.ToString.class,
@@ -64,7 +64,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Sun Mar 03 10:11:12 PST 1901</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Sun Mar 03 10:11:12 PST 1901</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 1 */
"DateSwap.ToString/dateArray",
dateArray,
DateSwap.ToString.class,
@@ -81,16 +81,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@('Sun Mar 03 10:11:12 PST 1901')",
/* UonT */ "@('Sun Mar 03 10:11:12 PST 1901')",
/* UonR */ "@(\n\t'Sun Mar 03 10:11:12 PST 1901'\n)",
- /* UrlEnc */ "_value=@('Sun+Mar+03+10:11:12+PST+1901')",
- /* UrlEncT */ "_value=@('Sun+Mar+03+10:11:12+PST+1901')",
- /* UrlEncR */ "_value=@(\n\t'Sun+Mar+03+10:11:12+PST+1901'\n)",
+ /* UrlEnc */ "0='Sun+Mar+03+10:11:12+PST+1901'",
+ /* UrlEncT */ "0='Sun+Mar+03+10:11:12+PST+1901'",
+ /* UrlEncR */ "0='Sun+Mar+03+10:11:12+PST+1901'",
/* MsgPack */ "91BC53756E204D61722030332031303A31313A3132205053542031393031",
/* MsgPackT */ "91BC53756E204D61722030332031303A31313A3132205053542031393031",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Sun Mar 03 10:11:12 PST 1901</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 2 */
"DateSwap.ToString",
dateMap,
DateSwap.ToString.class,
@@ -116,7 +116,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>Sun Mar 03 10:11:12 PST 1901</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>Sun Mar 03 10:11:12 PST 1901</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 3 */
"DateSwap.ISO8601DT/singleDate",
singleDate,
DateSwap.ISO8601DT.class,
@@ -142,7 +142,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>1901-03-03T10:11:12-08:00</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>1901-03-03T10:11:12-08:00</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 4 */
"DateSwap.ISO8601DT/dateArray",
dateArray,
DateSwap.ISO8601DT.class,
@@ -159,16 +159,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@(1901-03-03T10:11:12-08:00)",
/* UonT */ "@(1901-03-03T10:11:12-08:00)",
/* UonR */ "@(\n\t1901-03-03T10:11:12-08:00\n)",
- /* UrlEnc */ "_value=@(1901-03-03T10:11:12-08:00)",
- /* UrlEncT */ "_value=@(1901-03-03T10:11:12-08:00)",
- /* UrlEncR */ "_value=@(\n\t1901-03-03T10:11:12-08:00\n)",
+ /* UrlEnc */ "0=1901-03-03T10:11:12-08:00",
+ /* UrlEncT */ "0=1901-03-03T10:11:12-08:00",
+ /* UrlEncR */ "0=1901-03-03T10:11:12-08:00",
/* MsgPack */ "91B9313930312D30332D30335431303A31313A31322D30383A3030",
/* MsgPackT */ "91B9313930312D30332D30335431303A31313A31322D30383A3030",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>1901-03-03T10:11:12-08:00</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 5 */
"DateSwap.ISO8601DT/dateMap",
dateMap,
DateSwap.ISO8601DT.class,
@@ -194,7 +194,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>1901-03-03T10:11:12-08:00</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>1901-03-03T10:11:12-08:00</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 6 */
"DateSwap.RFC2822DTZ/singleDate",
singleDate,
DateSwap.RFC2822DTZ.class,
@@ -220,7 +220,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Sun, 03 Mar 1901 18:11:12 GMT</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Sun, 03 Mar 1901 18:11:12 GMT</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 7 */
"DateSwap.RFC2822DTZ/dateArray",
dateArray,
DateSwap.RFC2822DTZ.class,
@@ -237,16 +237,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@('Sun, 03 Mar 1901 18:11:12 GMT')",
/* UonT */ "@('Sun, 03 Mar 1901 18:11:12 GMT')",
/* UonR */ "@(\n\t'Sun, 03 Mar 1901 18:11:12 GMT'\n)",
- /* UrlEnc */ "_value=@('Sun,+03+Mar+1901+18:11:12+GMT')",
- /* UrlEncT */ "_value=@('Sun,+03+Mar+1901+18:11:12+GMT')",
- /* UrlEncR */ "_value=@(\n\t'Sun,+03+Mar+1901+18:11:12+GMT'\n)",
+ /* UrlEnc */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
+ /* UrlEncT */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
+ /* UrlEncR */ "0='Sun,+03+Mar+1901+18:11:12+GMT'",
/* MsgPack */ "91BD53756E2C203033204D617220313930312031383A31313A313220474D54",
/* MsgPackT */ "91BD53756E2C203033204D617220313930312031383A31313A313220474D54",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Sun, 03 Mar 1901 18:11:12 GMT</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 8 */
"DateSwap.RFC2822DTZ/dateMap",
dateMap,
DateSwap.RFC2822DTZ.class,
@@ -272,7 +272,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>Sun, 03 Mar 1901 18:11:12 GMT</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>Sun, 03 Mar 1901 18:11:12 GMT</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 9 */
"DateLongSwap",
singleDate,
DateLongSwap.class,
@@ -298,7 +298,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>-2172116928000</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>-2172116928000</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 10 */
"DateLongSwap/dateArray",
dateArray,
DateLongSwap.class,
@@ -315,16 +315,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@(-2172116928000)",
/* UonT */ "@(-2172116928000)",
/* UonR */ "@(\n\t-2172116928000\n)",
- /* UrlEnc */ "_value=@(-2172116928000)",
- /* UrlEncT */ "_value=@(-2172116928000)",
- /* UrlEncR */ "_value=@(\n\t-2172116928000\n)",
+ /* UrlEnc */ "0=-2172116928000",
+ /* UrlEncT */ "0=-2172116928000",
+ /* UrlEncR */ "0=-2172116928000",
/* MsgPack */ "91D3FFFFFE0643BDFA00",
/* MsgPackT */ "91D3FFFFFE0643BDFA00",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>-2172116928000</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>-2172116928000</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>-2172116928000</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 11 */
"DateLongSwap/dateMap",
dateMap,
DateLongSwap.class,
@@ -350,7 +350,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo>-2172116928000</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo>-2172116928000</jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 12 */
"DateMapSwap/singleDate",
singleDate,
DateMapSwap.class,
@@ -376,7 +376,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:time>-2172116928000</jp:time>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:time>-2172116928000</jp:time>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 13 */
"DateMapSwap/dateArray",
dateArray,
DateMapSwap.class,
@@ -393,16 +393,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@((time=-2172116928000))",
/* UonT */ "@((time=-2172116928000))",
/* UonR */ "@(\n\t(\n\t\ttime=-2172116928000\n\t)\n)",
- /* UrlEnc */ "_value=@((time=-2172116928000))",
- /* UrlEncT */ "_value=@((time=-2172116928000))",
- /* UrlEncR */ "_value=@(\n\t(\n\t\ttime=-2172116928000\n\t)\n)",
+ /* UrlEnc */ "0=(time=-2172116928000)",
+ /* UrlEncT */ "0=(time=-2172116928000)",
+ /* UrlEncR */ "0=(\n\ttime=-2172116928000\n)",
/* MsgPack */ "9181A474696D65D3FFFFFE0643BDFA00",
/* MsgPackT */ "9181A474696D65D3FFFFFE0643BDFA00",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li rdf:parseType='Resource'>\n <jp:time>-2172116928000</jp:time>\n </rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 14 */
"DateMapSwap/dateMap",
dateMap,
DateMapSwap.class,
@@ -428,7 +428,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<jp:foo rdf:parseType='Resource'>\n<jp:time>-2172116928000</jp:time>\n</jp:foo>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <jp:foo rdf:parseType='Resource'>\n <jp:time>-2172116928000</jp:time>\n </jp:foo>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 15 */
"DateSwap.DateMedium/singleDate",
singleDate,
DateSwap.DateMedium.class,
@@ -454,7 +454,7 @@ public class DateSwapComboTest extends ComboTest {
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Description>\n<j:value>Mar 3, 1901</j:value>\n</rdf:Description>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Description>\n <j:value>Mar 3, 1901</j:value>\n </rdf:Description>\n</rdf:RDF>\n",
},
- {
+ { /* 16 */
"DateSwap.DateMedium/dateArray",
dateArray,
DateSwap.DateMedium.class,
@@ -471,16 +471,16 @@ public class DateSwapComboTest extends ComboTest {
/* Uon */ "@('Mar 3, 1901')",
/* UonT */ "@('Mar 3, 1901')",
/* UonR */ "@(\n\t'Mar 3, 1901'\n)",
- /* UrlEnc */ "_value=@('Mar+3,+1901')",
- /* UrlEncT */ "_value=@('Mar+3,+1901')",
- /* UrlEncR */ "_value=@(\n\t'Mar+3,+1901'\n)",
+ /* UrlEnc */ "0='Mar+3,+1901'",
+ /* UrlEncT */ "0='Mar+3,+1901'",
+ /* UrlEncR */ "0='Mar+3,+1901'",
/* MsgPack */ "91AB4D617220332C2031393031",
/* MsgPackT */ "91AB4D617220332C2031393031",
/* RdfXml */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Mar 3, 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlT */ "<rdf:RDF>\n<rdf:Seq>\n<rdf:li>Mar 3, 1901</rdf:li>\n</rdf:Seq>\n</rdf:RDF>\n",
/* RdfXmlR */ "<rdf:RDF>\n <rdf:Seq>\n <rdf:li>Mar 3, 1901</rdf:li>\n </rdf:Seq>\n</rdf:RDF>\n",
},
- {
+ { /* 17 */
"DateSwap.DateMedium/dateMap",
dateMap,
DateSwap.DateMedium.class,
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingSerializerTest.java
----------------------------------------------------------------------
diff --git a/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingSerializerTest.java b/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingSerializerTest.java
index 91dc1a6..66e50dc 100755
--- a/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingSerializerTest.java
+++ b/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingSerializerTest.java
@@ -81,8 +81,8 @@ public class UrlEncodingSerializerTest {
// Empty array
// Top level
t = new String[0];
- assertEquals("_value=@()", s.serialize(t));
- assertEquals("_value=@()", sr.serialize(t));
+ assertEquals("", s.serialize(t));
+ assertEquals("", sr.serialize(t));
// 2nd level in map
t = new ObjectMap("{x:[]}");
@@ -91,14 +91,14 @@ public class UrlEncodingSerializerTest {
// Empty 2 dimensional array
t = new String[1][0];
- assertEquals("_value=@(@())", s.serialize(t));
- assertEquals("_value=@(\n\t@()\n)", sr.serialize(t));
+ assertEquals("0=@()", s.serialize(t));
+ assertEquals("0=@()", sr.serialize(t));
// Array containing empty string
// Top level
t = new String[]{""};
- assertEquals("_value=@('')", s.serialize(t));
- assertEquals("_value=@(\n\t''\n)", sr.serialize(t));
+ assertEquals("0=''", s.serialize(t));
+ assertEquals("0=''", sr.serialize(t));
// 2nd level
t = new ObjectMap("{x:['']}");
@@ -107,8 +107,8 @@ public class UrlEncodingSerializerTest {
// Array containing 3 empty strings
t = new String[]{"","",""};
- assertEquals("_value=@('','','')", s.serialize(t));
- assertEquals("_value=@(\n\t'',\n\t'',\n\t''\n)", sr.serialize(t));
+ assertEquals("0=''&1=''&2=''", s.serialize(t));
+ assertEquals("0=''\n&1=''\n&2=''", sr.serialize(t));
// String containing \u0000
// Top level
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/BeanSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanSession.java b/juneau-core/src/main/java/org/apache/juneau/BeanSession.java
index b033324..1fb0464 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanSession.java
@@ -732,7 +732,7 @@ public class BeanSession extends Session {
if (m == null)
return null;
T bean = null;
- if (m.constructorArgs.length == 0)
+ if (m.constructorArgs.length == 0)
bean = newBean(outer, c);
return new BeanMap<T>(this, bean, m);
}
@@ -774,7 +774,7 @@ public class BeanSession extends Session {
return null;
try {
T o = (T)m.newBean(outer);
- if (o == null)
+ if (o == null)
throw new BeanRuntimeException(c, "Class does not have a no-arg constructor.");
return o;
} catch (BeanRuntimeException e) {
@@ -843,13 +843,13 @@ public class BeanSession extends Session {
}
/**
- * Given an array of {@link Class} objects, returns an array of corresponding {@link ClassMeta} objects.
+ * Given an array of {@link Type} objects, returns an array of corresponding {@link ClassMeta} objects.
* Constructs a new array on each call.
*
* @param classes The array of classes to get class metas for.
* @return An array of {@link ClassMeta} objects corresponding to the classes. Never <jk>null</jk>.
*/
- public final ClassMeta<?>[] getClassMetas(Class<?>[] classes) {
+ public final ClassMeta<?>[] getClassMetas(Type[] classes) {
assertFieldNotNull(classes, "classes");
ClassMeta<?>[] cm = new ClassMeta<?>[classes.length];
for (int i = 0; i < classes.length; i++)
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index e320777..fa3fed1 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -54,7 +54,7 @@ public final class ClassMeta<T> implements Type {
/** Class categories. */
enum ClassCategory {
- MAP, COLLECTION, CLASS, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM
+ MAP, COLLECTION, CLASS, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM, VOID
}
final Class<T> innerClass; // The class being wrapped.
@@ -83,6 +83,7 @@ public final class ClassMeta<T> implements Type {
private final Object primitiveDefault; // Default value for primitive type classes.
private final Map<String,Method>
remoteableMethods, // Methods annotated with @Remoteable. Contains all public methods if class is annotated with @Remotable.
+ proxyableMethods, // Remoteable methods only if at least one method is marked @Remoteable, otherwise all public methods.
publicMethods; // All public methods, including static methods.
private final PojoSwap<?,?>[] childPojoSwaps; // Any PojoSwaps where the normal type is a subclass of this class.
private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
@@ -159,6 +160,7 @@ public final class ClassMeta<T> implements Type {
this.primitiveDefault = builder.primitiveDefault;
this.publicMethods = builder.publicMethods;
this.remoteableMethods = builder.remoteableMethods;
+ this.proxyableMethods = builder.proxyableMethods;
this.beanFilter = beanFilter;
this.pojoSwap = builder.pojoSwap;
this.extMeta = new MetadataMap();
@@ -208,6 +210,7 @@ public final class ClassMeta<T> implements Type {
this.isMemberClass = mainType.isMemberClass;
this.primitiveDefault = mainType.primitiveDefault;
this.remoteableMethods = mainType.remoteableMethods;
+ this.proxyableMethods = mainType.proxyableMethods;
this.publicMethods = mainType.publicMethods;
this.beanContext = mainType.beanContext;
this.serializedClassMeta = this;
@@ -253,7 +256,8 @@ public final class ClassMeta<T> implements Type {
Object primitiveDefault = null;
Map<String,Method>
publicMethods = new LinkedHashMap<String,Method>(),
- remoteableMethods = null;
+ remoteableMethods = null,
+ proxyableMethods = null;
ClassMeta<?>
keyType = null,
valueType = null,
@@ -294,6 +298,8 @@ public final class ClassMeta<T> implements Type {
}
else if (c == Character.TYPE)
cc = CHAR;
+ else if (c == void.class || c == Void.class)
+ cc = VOID;
} else {
if (isParentClass(Delegate.class, c))
isDelegate = true;
@@ -479,7 +485,7 @@ public final class ClassMeta<T> implements Type {
publicMethods.put(ClassUtils.getMethodSignature(m), m);
if (c.getAnnotation(Remoteable.class) != null) {
- remoteableMethods = publicMethods;
+ remoteableMethods = proxyableMethods = publicMethods;
} else {
for (Method m : c.getMethods()) {
if (m.getAnnotation(Remoteable.class) != null) {
@@ -488,6 +494,7 @@ public final class ClassMeta<T> implements Type {
remoteableMethods.put(ClassUtils.getMethodSignature(m), m);
}
}
+ proxyableMethods = (remoteableMethods != null ? remoteableMethods : publicMethods);
}
if (innerClass != Object.class) {
@@ -1050,6 +1057,15 @@ public final class ClassMeta<T> implements Type {
}
/**
+ * Returns <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
+ *
+ * @return <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
+ */
+ public boolean isVoid() {
+ return cc == VOID;
+ }
+
+ /**
* Returns <jk>true</jk> if instance of this object can be <jk>null</jk>.
* <p>
* Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented
@@ -1099,6 +1115,17 @@ public final class ClassMeta<T> implements Type {
}
/**
+ * All methods on this class that can be exposed as a proxy method.
+ * <p>
+ * Same as {@link #getRemoteableMethods()} except returns all public methods if class is not annotated with {@link Remoteable @Remotable}.
+ *
+ * @return All proxyable methods on this class.
+ */
+ public Map<String,Method> getProxyableMethods() {
+ return proxyableMethods;
+ }
+
+ /**
* All public methods on this class including static methods.
* Keys are method signatures.
*
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
index ef73860..75f2760 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
@@ -111,6 +111,9 @@ public class HtmlParser extends XmlParser {
boolean isValid = true;
HtmlTag tag = (event == CHARACTERS ? null : HtmlTag.forString(r.getName().getLocalPart(), false));
+ if (tag == HTML)
+ tag = skipToData(r);
+
if (isEmpty) {
o = "";
} else if (tag == null || tag.isOneOf(BR,BS,FF,SP)) {
@@ -164,6 +167,12 @@ public class HtmlParser extends XmlParser {
isValid = false;
skipTag(r, xBOOLEAN);
+ } else if (tag == P) {
+ String text = session.getElementText(r);
+ if (! "No Results".equals(text))
+ isValid = false;
+ skipTag(r, xP);
+
} else if (tag == NULL) {
skipTag(r, NULL);
skipTag(r, xNULL);
@@ -246,6 +255,26 @@ public class HtmlParser extends XmlParser {
return (T)o;
}
+ /**
+ * For parsing output from HtmlDocSerializer, this skips over the head, title, and links.
+ */
+ private static HtmlTag skipToData(XMLStreamReader r) throws XMLStreamException {
+ while (true) {
+ int event = r.next();
+ if (event == START_ELEMENT && "div".equals(r.getLocalName()) && "data".equals(r.getAttributeValue(null, "id"))) {
+ r.nextTag();
+ event = r.getEventType();
+ boolean isEmpty = (event == END_ELEMENT);
+ // Skip until we find a start element, end document, or non-empty text.
+ if (! isEmpty)
+ event = skipWs(r);
+ if (event == END_DOCUMENT)
+ throw new XMLStreamException("Unexpected end of stream looking for data.", r.getLocation());
+ return (event == CHARACTERS ? null : HtmlTag.forString(r.getName().getLocalPart(), false));
+ }
+ }
+ }
+
private static String getAttribute(XMLStreamReader r, String name, String def) {
for (int i = 0; i < r.getAttributeCount(); i++)
if (r.getAttributeLocalName(i).equals(name))
@@ -327,10 +356,19 @@ public class HtmlParser extends XmlParser {
* Postcondition: Pointing at next START_ELEMENT or END_DOCUMENT event.
*/
private Object[] parseArgs(HtmlParserSession session, XMLStreamReader r, ClassMeta<?>[] argTypes) throws Exception {
+ HtmlTag tag = HtmlTag.forEvent(r);
+
+ // Special case:
+ // Serializing args containing a single bean (or multiple beans of the same type) will end up serialized as a <table _type='array'>
+ if (tag == TABLE) {
+ List<Object> l = (List<Object>)parseAnything(session, session.getClassMeta(List.class, argTypes[0]), r, session.getOuter(), true, null);
+ return l.toArray(new Object[l.size()]);
+ }
+
Object[] o = new Object[argTypes.length];
int i = 0;
while (true) {
- HtmlTag tag = nextTag(r, LI, xUL);
+ tag = nextTag(r, LI, xUL);
if (tag == xUL)
break;
o[i] = parseAnything(session, argTypes[i], r, session.getOuter(), false, null);
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
index efa36e2..74a98ce 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
@@ -40,6 +40,8 @@ enum HtmlTag {
FF(13,"<ff>"), // formfeed
BS(14,"<bs>"), // backspace
SP(17, "<sp>"), // space
+ P(18, "<p>"),
+ HTML(19, "<html>"),
xTABLE(-1,"</table>"),
xTR(-2,"</tr>"),
xTH(-3,"</th>"),
@@ -54,7 +56,9 @@ enum HtmlTag {
xBR(-12,"</br>"),
xFF(-13,"</ff>"),
xBS(-14,"</bs>"),
- xSP(-17, "</sp>");
+ xSP(-17, "</sp>"),
+ xP(-18, "</p>"),
+ xHTML(-19, "</html>");
private Map<Integer,HtmlTag> cache = new HashMap<Integer,HtmlTag>();
@@ -121,6 +125,10 @@ enum HtmlTag {
}
else if (c == 'f')
t = (end ? xFF : FF);
+ else if (c == 'p')
+ t = (end ? xP : P);
+ else if (c == 'h')
+ t = (end ? xHTML : HTML);
if (t == null)
throw new XMLStreamException("Unknown tag '"+tag+"' encountered");
return t;
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 4ba239f..39bf16b 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -624,4 +624,45 @@ public final class ClassUtils {
// private Class<?> findClass(String name) throws ClassNotFoundException {
// return classLoader == null ? Class.forName(name) : Class.forName(name, true, classLoader);
// }
+
+ /**
+ * Returns a {@link MethodInfo} bean that describes the specified method.
+ * @param m The method to describe.
+ * @return The bean with information about the method.
+ */
+ public static MethodInfo getMethodInfo(Method m) {
+ return new MethodInfo(m);
+ }
+
+ /**
+ * Returns {@link MethodInfo} beans that describe the specified methods.
+ * @param m The methods to describe.
+ * @return The beans with information about the methods.
+ */
+ public static MethodInfo[] getMethodInfo(Collection<Method> m) {
+ MethodInfo[] mi = new MethodInfo[m.size()];
+ int i = 0;
+ for (Method mm : m)
+ mi[i++] = getMethodInfo(mm);
+ return mi;
+ }
+
+ /**
+ * Simple bean that shows the name, parameter types, and return type of a method.
+ */
+ @SuppressWarnings("javadoc")
+ public static class MethodInfo {
+ public final String methodName;
+ public final String[] parameterTypes;
+ public final String returnType;
+
+ MethodInfo(Method m) {
+ methodName = m.getName();
+ Type[] pt = m.getGenericParameterTypes();
+ parameterTypes = new String[pt.length];
+ for (int i = 0; i < pt.length; i++)
+ parameterTypes[i] = BeanContext.DEFAULT.getClassMeta(pt[i]).toString();
+ returnType = BeanContext.DEFAULT.getClassMeta(m.getGenericReturnType()).toString();
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
index ce4db63..77e0b9c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackParser.java
@@ -196,7 +196,24 @@ public class MsgPackParser extends InputStreamParser {
return (T)o;
}
+ private Object[] parseArgs(MsgPackParserSession session, MsgPackInputStream is, ClassMeta<?>[] argTypes) throws Exception {
+ Object[] o = new Object[argTypes.length];
+ DataType dt = is.readDataType();
+ int length = (int)is.readLength();
+
+ if (dt != ARRAY)
+ throw new ParseException("Expected ARRAY but was {0}", dt);
+ if (length != argTypes.length)
+ throw new ParseException("Expected array length {0} but was {1}", argTypes.length, length);
+
+ for (int i = 0; i < length; i++)
+ o[i] = parseAnything(session, argTypes[i], is, null, null);
+
+ return o;
+ }
+
+
//--------------------------------------------------------------------------------
// Entry point methods
//--------------------------------------------------------------------------------
@@ -213,4 +230,12 @@ public class MsgPackParser extends InputStreamParser {
T o = parseAnything(s, type, is, s.getOuter(), null);
return o;
}
+
+ @Override /* ReaderParser */
+ protected Object[] doParseArgs(ParserSession session, ClassMeta<?>[] argTypes) throws Exception {
+ MsgPackParserSession s = (MsgPackParserSession)session;
+ MsgPackInputStream is = s.getInputStream();
+ Object[] a = parseArgs(s, is, argTypes);
+ return a;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
index 53ec4c6..bb79146 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
@@ -272,6 +272,7 @@ public abstract class Parser extends CoreObject {
* <br>Ignored if the main type is not a map or collection.
* @return The parsed object.
* @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+ * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
*/
@SuppressWarnings("unchecked")
public final <T> T parse(Object input, Type type, Type...args) throws ParseException {
@@ -288,11 +289,14 @@ public abstract class Parser extends CoreObject {
* ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
*
* <jc>// Parse into a string.</jc>
- * MyBean b = p.parse(json, String.<jk>class</jk>);
+ * String s = p.parse(json, String.<jk>class</jk>);
*
* <jc>// Parse into a bean.</jc>
* MyBean b = p.parse(json, MyBean.<jk>class</jk>);
*
+ * <jc>// Parse into a bean array.</jc>
+ * MyBean[] ba = p.parse(json, MyBean[].<jk>class</jk>);
+ *
* <jc>// Parse into a linked-list of objects.</jc>
* List l = p.parse(json, LinkedList.<jk>class</jk>);
*
@@ -477,7 +481,6 @@ public abstract class Parser extends CoreObject {
* @param argTypes Specifies the type of objects to create for each entry in the array.
* @return An array of parsed objects.
* @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
- * @throws UnsupportedOperationException If not implemented.
*/
public final Object[] parseArgs(Object input, ClassMeta<?>[] argTypes) throws ParseException {
if (argTypes == null || argTypes.length == 0)
@@ -495,6 +498,29 @@ public abstract class Parser extends CoreObject {
}
/**
+ * Same as {@link #parseArgs(Object, ClassMeta[])} except allows you to pass in {@link Class} objects.
+ *
+ * @param input The input. Subclasses can support different input types.
+ * @param argTypes Specifies the type of objects to create for each entry in the array.
+ * @return An array of parsed objects.
+ * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type.
+ */
+ public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
+ if (argTypes == null || argTypes.length == 0)
+ return new Object[0];
+ ParserSession session = createSession(input);
+ try {
+ return doParseArgs(session, session.getClassMetas(argTypes));
+ } catch (ParseException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ParseException(session, e);
+ } finally {
+ session.close();
+ }
+ }
+
+ /**
* Implementation method.
* Default implementation throws an {@link UnsupportedOperationException}.
* @param session The runtime session object returned by {@link #createSession(Object, ObjectMap, Method, Object, Locale, TimeZone, MediaType)}.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
index 64f9253..ac44c84 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
@@ -36,6 +36,18 @@ public class ParserGroupBuilder {
}
/**
+ * Create an empty parser group using the specified property store for settings.
+ * <p>
+ * Note: Modifying the specified property store externally will also modify it here.
+ *
+ * @param propertyStore The property store containing all settings common to all parsers in this group.
+ */
+ public ParserGroupBuilder(PropertyStore propertyStore) {
+ this.parsers = new ArrayList<Object>();
+ this.propertyStore = propertyStore;
+ }
+
+ /**
* Clone an existing parser group builder.
* @param copyFrom The parser group that we're copying settings and parsers from.
*/
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
index b639358..5521a9d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
+++ b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
@@ -36,6 +36,18 @@ public class SerializerGroupBuilder {
}
/**
+ * Create an empty serializer group using the specified property store for settings.
+ * <p>
+ * Note: Modifying the specified property store externally will also modify it here.
+ *
+ * @param propertyStore The property store containing all settings common to all serializers in this group.
+ */
+ public SerializerGroupBuilder(PropertyStore propertyStore) {
+ this.serializers = new ArrayList<Object>();
+ this.propertyStore = propertyStore;
+ }
+
+ /**
* Clone an existing serializer group builder.
* @param copyFrom The serializer group that we're copying settings and serializers from.
*/
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/uon/UonParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonParser.java b/juneau-core/src/main/java/org/apache/juneau/uon/UonParser.java
index b4ed5ea..817811d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonParser.java
@@ -125,6 +125,10 @@ public class UonParser extends ReaderParser {
else if (sType.isPrimitive())
o = sType.getPrimitiveDefault();
// Otherwise, leave null.
+ } else if (sType.isVoid()) {
+ String s = parseString(session, r, isUrlParamValue);
+ if (s != null)
+ throw new ParseException(session, "Expected ''null'' for void value, but was ''{0}''.", s);
} else if (sType.isObject()) {
if (c == '(') {
ObjectMap m = new ObjectMap(session);
@@ -138,10 +142,12 @@ public class UonParser extends ReaderParser {
if (c != '\'') {
if ("true".equals(s) || "false".equals(s))
o = Boolean.valueOf(s);
- else if (StringUtils.isNumeric(s))
- o = StringUtils.parseNumber(s, Number.class);
- else
- o = s;
+ else if (! "null".equals(s)) {
+ if (StringUtils.isNumeric(s))
+ o = StringUtils.parseNumber(s, Number.class);
+ else
+ o = s;
+ }
} else {
o = s;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
index f6de298..89d68ea 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
@@ -112,9 +112,9 @@ public class UrlEncodingParser extends UonParser {
o = session.cast(m, null, eType);
else if (m.containsKey("_value"))
o = session.convertToType(m.get("_value"), sType);
- else if (sType.isCollection()) {
+ else if (sType.isCollection() || sType.isArray()) {
// ?1=foo&2=bar...
- Collection c2 = sType.canCreateNewInstance() ? (Collection)sType.newInstance() : new ObjectList(session);
+ Collection c2 = (sType.isArray() || ! sType.canCreateNewInstance(outer)) ? new ObjectList(session) : (Collection)sType.newInstance();
Map<Integer,Object> t = new TreeMap<Integer,Object>();
for (Map.Entry<String,Object> e : m.entrySet()) {
String k = e.getKey();
@@ -122,7 +122,7 @@ public class UrlEncodingParser extends UonParser {
t.put(Integer.valueOf(k), session.convertToType(e.getValue(), sType.getElementType()));
}
c2.addAll(t.values());
- o = c2;
+ o = (sType.isArray() ? ArrayUtils.toArray(c2, sType.getElementType().getInnerClass()) : c2);
} else {
if (sType.getNotABeanReason() != null)
throw new ParseException(session, "Class ''{0}'' could not be instantiated as application/x-www-form-urlencoded. Reason: ''{1}''", sType, sType.getNotABeanReason());
@@ -413,18 +413,76 @@ public class UrlEncodingParser extends UonParser {
}
private Object[] parseArgs(UrlEncodingParserSession session, ParserReader r, ClassMeta<?>[] argTypes) throws Exception {
- // TODO - This can be made more efficient.
- ClassMeta<TreeMap<Integer,String>> cm = session.getClassMeta(TreeMap.class, Integer.class, String.class);
- TreeMap<Integer,String> m = parseAnything(session, cm, r, session.getOuter());
- Object[] vals = m.values().toArray(new Object[m.size()]);
- if (vals.length != argTypes.length)
- throw new ParseException(session, "Argument lengths don't match. vals={0}, argTypes={1}", vals.length, argTypes.length);
- for (int i = 0; i < vals.length; i++) {
- String s = String.valueOf(vals[i]);
- vals[i] = super.parseAnything(session, argTypes[i], new UonReader(s, false), session.getOuter(), true, null);
+
+ int c = r.peekSkipWs();
+ if (c == '?')
+ r.read();
+
+ Object[] vals = new Object[argTypes.length];
+
+ final int S1=1; // Looking for attrName start.
+ final int S2=2; // Found attrName end, looking for =.
+ final int S3=3; // Found =, looking for valStart.
+ final int S4=4; // Looking for & or end.
+ boolean isInEscape = false;
+
+ int state = S1;
+ Integer currIdx = 0;
+ while (c != -1) {
+ c = r.read();
+ if (! isInEscape) {
+ if (state == S1) {
+ if (c == -1)
+ return vals;
+ r.unread();
+ Object attr = parseAttr(session, r, true);
+ currIdx = Integer.parseInt(attr.toString());
+ if (currIdx >= vals.length)
+ throw new ParseException(session, "Out-of-range index encountered. args length={0}, index={1}", vals.length, currIdx);
+ state = S2;
+ c = 0; // Avoid isInEscape if c was '\'
+ } else if (state == S2) {
+ if (c == '\u0002')
+ state = S3;
+ else if (c == -1 || c == '\u0001') {
+ vals[currIdx] = null;
+ if (c == -1)
+ return vals;
+ state = S1;
+ }
+ } else if (state == S3) {
+ if (c == -1 || c == '\u0001') {
+ vals[currIdx] = convertAttrToType(session, null, "", argTypes[currIdx]);
+ if (c == -1)
+ return vals;
+ state = S1;
+ } else {
+ // For performance, we bypass parseAnything for string values.
+ vals[currIdx] = argTypes[currIdx].isString() ? super.parseString(session, r.unread(), true) : super.parseAnything(session, argTypes[currIdx], r.unread(), null, true, null);
+
+ state = S4;
+ c = 0; // Avoid isInEscape if c was '\'
+ }
+ } else if (state == S4) {
+ if (c == '\u0001')
+ state = S1;
+ else if (c == -1) {
+ return vals;
+ }
+ }
+ }
+ isInEscape = (c == '\\' && ! isInEscape);
}
+ if (state == S1)
+ throw new ParseException(session, "Could not find attribute name on object.");
+ if (state == S2)
+ throw new ParseException(session, "Could not find '=' following attribute name on object.");
+ if (state == S3)
+ throw new ParseException(session, "Dangling '=' found in object entry");
+ if (state == S4)
+ throw new ParseException(session, "Could not find end of object.");
- return vals;
+ return null; // Unreachable.
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 665ff27..222ad7c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -239,8 +239,9 @@ public class UrlEncodingSerializer extends UonSerializer {
serializeMap(session, out, (Map)o, sType);
} else if (sType.isBean()) {
serializeBeanMap(session, out, session.toBeanMap(o), typeName);
- } else if (sType.isCollection()) {
- serializeMap(session, out, getCollectionMap((Collection)o), session.getClassMeta(Map.class, Integer.class, sType.getElementType()));
+ } else if (sType.isCollection() || sType.isArray()) {
+ Map m = sType.isCollection() ? getCollectionMap((Collection)o) : getCollectionMap(o);
+ serializeCollectionMap(session, out, m, session.getClassMeta(Map.class, Integer.class, Object.class));
} else {
// All other types can't be serialized as key/value pairs, so we create a
// mock key/value pair with a "_value" key.
@@ -252,6 +253,9 @@ public class UrlEncodingSerializer extends UonSerializer {
return out;
}
+ /**
+ * Converts a Collection into an integer-indexed map.
+ */
private static Map<Integer,Object> getCollectionMap(Collection<?> c) {
Map<Integer,Object> m = new TreeMap<Integer,Object>();
int i = 0;
@@ -260,6 +264,16 @@ public class UrlEncodingSerializer extends UonSerializer {
return m;
}
+ /**
+ * Converts an array into an integer-indexed map.
+ */
+ private static Map<Integer,Object> getCollectionMap(Object array) {
+ Map<Integer,Object> m = new TreeMap<Integer,Object>();
+ for (int i = 0; i < Array.getLength(array); i++)
+ m.put(i, Array.get(array, i));
+ return m;
+ }
+
@SuppressWarnings({ "rawtypes", "unchecked" })
private SerializerWriter serializeMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception {
@@ -270,13 +284,9 @@ public class UrlEncodingSerializer extends UonSerializer {
int depth = session.getIndent();
boolean addAmp = false;
- Iterator mapEntries = m.entrySet().iterator();
-
- while (mapEntries.hasNext()) {
- Map.Entry e = (Map.Entry) mapEntries.next();
- Object value = e.getValue();
+ for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
Object key = session.generalize(e.getKey(), keyType);
-
+ Object value = e.getValue();
if (session.shouldUseExpandedParams(value)) {
Iterator i = value instanceof Collection ? ((Collection)value).iterator() : ArrayUtils.iterator(value);
@@ -299,6 +309,25 @@ public class UrlEncodingSerializer extends UonSerializer {
return out;
}
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private SerializerWriter serializeCollectionMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception {
+
+ ClassMeta<?> valueType = type.getValueType();
+
+ int depth = session.getIndent();
+ boolean addAmp = false;
+
+ for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) {
+ if (addAmp)
+ out.cr(depth).append('&');
+ out.append(e.getKey()).append('=');
+ super.serializeAnything(session, out, e.getValue(), valueType, null, null);
+ addAmp = true;
+ }
+
+ return out;
+ }
+
@SuppressWarnings({ "rawtypes" })
private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
int depth = session.getIndent();
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/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 9a959d0..66952a8 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -5723,6 +5723,8 @@
<li>New {@link org.apache.juneau.svl.vars.SwitchVar $SWITCH} variable for switch block logic.
<li>Whitespace wasn't being ignored in some cases.
</ul>
+ <li>{@link org.apache.juneau.html.HtmlParser} can now parse full body contents generated by {@link org.apache.juneau.html.HtmlDocSerializer}.
+ <li>Parse-args supported added to {@link org.apache.juneau.msgpack.MsgPackParser} to allow it to be used in remoteable proxies.
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
@@ -5772,11 +5774,44 @@
<li>{@link org.apache.juneau.rest.annotation.RestResource#stylesheet()} can now take in a comma-delimited list of stylesheet paths.
<li>{@link org.apache.juneau.rest.StreamResource} can now contain multiple sources from a variety of source types (e.g. <code><jk>byte</jk>[]</code> arrays, <code>InputStreams</code>, <code>Files</code>, etc...)
and is now immutable. It also includes a new {@link org.apache.juneau.rest.StreamResource.Builder} class.
+ <li>Simplified remoteable proxies using the <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code> annotation on REST methods.
+ Used to expose interface proxies without the need for {@link org.apache.juneau.rest.remoteable.RemoteableServlet}.
+ <p class='bcode'>
+ <jc>// Server side</jc>
+ <ja>@RestMethod</ja>(name=<js>"PROXY"</js>, path=<js>"/myproxy/*"</js>)
+ <jk>public</jk> IAddressBook getProxy() {
+ <jk>return</jk> <jf>addressBook</jf>;
+ }
+
+ <jc>// Client side</jc>
+ RestClient client = <jk>new</jk> RestClientBuilder().rootUrl(<jf>samplesUrl</jf>).build();
+ IAddressBook ab = client.getRemoteableProxy(IAddressBook.<jk>class</jk>, <js>"/addressBook/myproxy"</js>);
+ </p>
+ See {@link org.apache.juneau.rest.annotation.RestMethod#name()} for more information.
+ <li>{@link org.apache.juneau.rest.RestRequest#toString()} can be called at any time to view the headers and content of the request
+ without affecting functionality. Very useful for debugging.
</ul>
<h6 class='topic'>org.apache.juneau.rest.client</h6>
<ul class='spaced-list'>
<li>Revamped the client API to use builders.
+ <li>New methods added to {@link org.apache.juneau.rest.client.RestCall}:
+ <ul>
+ <li>{@link org.apache.juneau.rest.client.RestCall#serializer(Serializer)} - Override the serializer defined on the client for a single call.
+ <li>{@link org.apache.juneau.rest.client.RestCall#parser(Parser)} - Override the parser defined on the client for a single call.
+ </ul>
+ <li>New methods added to {@link org.apache.juneau.rest.client.RestClient}:
+ <ul>
+ <li>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class,Object)} - For interface proxies defined using <code><ja>@RestMethod</ja>(name=<js>"PROXY"</js>)</code>.
+ <li>{@link org.apache.juneau.rest.client.RestClient#getRemoteableProxy(Class,Object,Serializer,Parser)} - Same as above, but overrides the serializer and parser defined on the client.
+ </ul>
+ <li>New methods added to {@link org.apache.juneau.rest.client.RestClientBuilder}:
+ <ul>
+ <li>{@link org.apache.juneau.rest.client.RestClientBuilder#noTrace()} - Adds a <code>No-Trace: true</code> header on all requests to prevent
+ the servlet from logging errors.
+ Useful for testing scenarios when you don't want the console to end up showing errors done on purpose.
+ <li>{@link org.apache.juneau.rest.client.RestClientBuilder#debug(boolean)} now adds a <code>Debug: true</code> header on all requests.
+ </ul>
</ul>
<h6 class='topic'>org.apache.juneau.microservice</h6>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/AddressBook.java
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/AddressBook.java b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/AddressBook.java
index 28935df..ede24f2 100755
--- a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/AddressBook.java
+++ b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/AddressBook.java
@@ -35,6 +35,27 @@ public class AddressBook extends LinkedList<Person> implements IAddressBook {
public AddressBook(URI uri) throws Exception {
this.uri = uri;
}
+
+ @Override /* IAddressBook */
+ public void init() throws Exception {
+ clear();
+ createPerson(
+ new CreatePerson(
+ "Barack Obama",
+ toCalendar("Aug 4, 1961"),
+ new CreateAddress("1600 Pennsylvania Ave", "Washington", "DC", 20500, true),
+ new CreateAddress("5046 S Greenwood Ave", "Chicago", "IL", 60615, false)
+ )
+ );
+ createPerson(
+ new CreatePerson(
+ "George Walker Bush",
+ toCalendar("Jul 6, 1946"),
+ new CreateAddress("43 Prairie Chapel Rd", "Crawford", "TX", 76638, true),
+ new CreateAddress("1600 Pennsylvania Ave", "Washington", "DC", 20500, false)
+ )
+ );
+ }
@Override /* IAddressBook */
public List<Person> getPeople() {
@@ -97,6 +118,4 @@ public class AddressBook extends LinkedList<Person> implements IAddressBook {
c.setTime(DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US).parse(birthDate));
return c;
}
-}
-
-
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
index 570fe06..1c7431a 100755
--- a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
+++ b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
@@ -19,6 +19,9 @@ import java.util.*;
* See {@link SampleRemoteableServlet}.
*/
public interface IAddressBook {
+
+ /** Initialize this address book with preset entries */
+ void init() throws Exception;
/** Return all people in the address book */
List<Person> getPeople();
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
index b8a7a50..4a49a60 100644
--- a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
+++ b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
@@ -13,7 +13,6 @@
package org.apache.juneau.examples.rest.addressbook;
import static javax.servlet.http.HttpServletResponse.*;
-import static org.apache.juneau.examples.addressbook.AddressBook.*;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
import static org.apache.juneau.jena.RdfCommonContext.*;
import static org.apache.juneau.jena.RdfSerializerContext.*;
@@ -74,23 +73,8 @@ public class AddressBookResource extends ResourceJena {
// Create the address book
addressBook = new AddressBook(java.net.URI.create(""));
- // Add some people to our address book by default
- addressBook.createPerson(
- new CreatePerson(
- "Barack Obama",
- toCalendar("Aug 4, 1961"),
- new CreateAddress("1600 Pennsylvania Ave", "Washington", "DC", 20500, true),
- new CreateAddress("5046 S Greenwood Ave", "Chicago", "IL", 60615, false)
- )
- );
- addressBook.createPerson(
- new CreatePerson(
- "George Walker Bush",
- toCalendar("Jul 6, 1946"),
- new CreateAddress("43 Prairie Chapel Rd", "Crawford", "TX", 76638, true),
- new CreateAddress("1600 Pennsylvania Ave", "Washington", "DC", 20500, false)
- )
- );
+ // Initialize it with some contents.
+ addressBook.init();
} catch (Exception e) {
throw new RuntimeException(e);
@@ -292,6 +276,15 @@ public class AddressBookResource extends ResourceJena {
}
/**
+ * [PROXY /*]
+ * Return a proxy interface to IAddressBook.
+ */
+ @RestMethod(name="PROXY", path="/proxy/*")
+ public IAddressBook getProxy() {
+ return addressBook;
+ }
+
+ /**
* [OPTIONS /*]
* View resource options
*/
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/9db2e03f/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/AddressBookResourceTest.java
----------------------------------------------------------------------
diff --git a/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/AddressBookResourceTest.java b/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/AddressBookResourceTest.java
index 5f3f602..8dfa7fd 100644
--- a/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/AddressBookResourceTest.java
+++ b/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/AddressBookResourceTest.java
@@ -258,4 +258,44 @@ public class AddressBookResourceTest extends RestTestcase {
assertObjectEquals("['B','r','ck Obama']", tokens);
}
}
+
+ //====================================================================================================
+ // Interface proxy tests
+ //====================================================================================================
+ @Test
+ public void testProxyInterface() throws Exception {
+
+ for (RestClient client : clients) {
+
+ List<Person> people;
+
+ IAddressBook ab = client.getRemoteableProxy(IAddressBook.class, "/addressBook/proxy");
+
+ // Reinitialize the resource
+ ab.init();
+
+ // Simple GETs
+ people = ab.getPeople();
+ assertEquals("Barack Obama", people.get(0).name);
+ assertEquals(76638, people.get(1).addresses.get(0).zip);
+
+ // POST a person
+ CreatePerson billClinton = new CreatePerson("Bill Clinton", AddressBook.toCalendar("Aug 19, 1946"),
+ new CreateAddress("a3","b3","c3",3,false)
+ );
+ ab.createPerson(billClinton);
+ people = ab.getPeople();
+ assertEquals(3, people.size());
+ Person p = people.get(2);
+ assertEquals("Bill Clinton", p.name);
+
+ // DELETE a person
+ ab.removePerson(p.id);
+ people = ab.getPeople();
+ assertEquals(2, people.size());
+
+ // Reinitialize the resource
+ ab.init();
+ }
+ }
}