You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/06/20 01:29:32 UTC
incubator-juneau git commit: Add @RemoteMethod(returns) annotation.
Repository: incubator-juneau
Updated Branches:
refs/heads/master 95ee1b536 -> 35cb8461b
Add @RemoteMethod(returns) annotation.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/35cb8461
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/35cb8461
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/35cb8461
Branch: refs/heads/master
Commit: 35cb8461bf0b4dab5214cb74843f28636827d809
Parents: 95ee1b5
Author: JamesBognar <ja...@apache.org>
Authored: Mon Jun 19 21:29:23 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Mon Jun 19 21:29:23 2017 -0400
----------------------------------------------------------------------
.../main/java/org/apache/juneau/ClassMeta.java | 45 +---------
.../org/apache/juneau/internal/ClassUtils.java | 31 +++++++
.../apache/juneau/remoteable/RemoteMethod.java | 29 +++++-
.../juneau/remoteable/RemoteableMethodMeta.java | 13 +++
.../apache/juneau/remoteable/ReturnValue.java | 25 ++++++
.../java/org/apache/juneau/utils/PojoQuery.java | 1 +
juneau-core/src/main/javadoc/overview.html | 1 +
.../apache/juneau/rest/client/RestClient.java | 17 +++-
.../rest/test/ThirdPartyProxyResource.java | 14 +++
.../juneau/rest/test/ThirdPartyProxyTest.java | 75 ++++++++++++++++
.../java/org/apache/juneau/rest/CallMethod.java | 2 +-
.../apache/juneau/rest/widget/QueryWidget.html | 92 ++++++++++++++------
12 files changed, 271 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/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 786d60a..1545511 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -111,15 +111,6 @@ public final class ClassMeta<T> implements Type {
private final BeanRegistry beanRegistry; // The bean registry of this class meta (if it has one).
private final ClassMeta<?>[] args; // Arg types if this is an array of args.
- private static final Boolean BOOLEAN_DEFAULT = false;
- private static final Character CHARACTER_DEFAULT = (char)0;
- private static final Short SHORT_DEFAULT = (short)0;
- private static final Integer INTEGER_DEFAULT = 0;
- private static final Long LONG_DEFAULT = 0l;
- private static final Float FLOAT_DEFAULT = 0f;
- private static final Double DOUBLE_DEFAULT = 0d;
- private static final Byte BYTE_DEFAULT = (byte)0;
-
private ReadWriteLock lock = new ReentrantReadWriteLock(false);
private Lock rLock = lock.readLock(), wLock = lock.writeLock();
@@ -521,41 +512,7 @@ public final class ClassMeta<T> implements Type {
}
}
- if (c.isPrimitive()) {
- if (c == Boolean.TYPE)
- primitiveDefault = BOOLEAN_DEFAULT;
- else if (c == Character.TYPE)
- primitiveDefault = CHARACTER_DEFAULT;
- else if (c == Short.TYPE)
- primitiveDefault = SHORT_DEFAULT;
- else if (c == Integer.TYPE)
- primitiveDefault = INTEGER_DEFAULT;
- else if (c == Long.TYPE)
- primitiveDefault = LONG_DEFAULT;
- else if (c == Float.TYPE)
- primitiveDefault = FLOAT_DEFAULT;
- else if (c == Double.TYPE)
- primitiveDefault = DOUBLE_DEFAULT;
- else if (c == Byte.TYPE)
- primitiveDefault = BYTE_DEFAULT;
- } else {
- if (c == Boolean.class)
- primitiveDefault = BOOLEAN_DEFAULT;
- else if (c == Character.class)
- primitiveDefault = CHARACTER_DEFAULT;
- else if (c == Short.class)
- primitiveDefault = SHORT_DEFAULT;
- else if (c == Integer.class)
- primitiveDefault = INTEGER_DEFAULT;
- else if (c == Long.class)
- primitiveDefault = LONG_DEFAULT;
- else if (c == Float.class)
- primitiveDefault = FLOAT_DEFAULT;
- else if (c == Double.class)
- primitiveDefault = DOUBLE_DEFAULT;
- else if (c == Byte.class)
- primitiveDefault = BYTE_DEFAULT;
- }
+ primitiveDefault = ClassUtils.getPrimitiveDefault(c);
for (Method m : c.getMethods())
if (isPublic(m) && isNotDeprecated(m))
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/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 0f52ed5..6a3e812 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
@@ -18,6 +18,7 @@ import java.lang.reflect.*;
import java.util.*;
import org.apache.juneau.*;
+import org.apache.juneau.utils.*;
/**
* Class-related utility methods.
@@ -923,4 +924,34 @@ public final class ClassUtils {
}
return l;
}
+
+ /**
+ * Returns the default value for the specified primitive class.
+ *
+ * @param primitiveClass The primitive class to get the default value for.
+ * @return The default value, or <jk>null</jk> if the specified class is not a primitive class.
+ */
+ public static Object getPrimitiveDefault(Class<?> primitiveClass) {
+ return primitiveDefaultMap.get(primitiveClass);
+ }
+
+ private static final Map<Class<?>,Object> primitiveDefaultMap = Collections.unmodifiableMap(
+ new AMap<Class<?>,Object>()
+ .append(Boolean.TYPE, false)
+ .append(Character.TYPE, (char)0)
+ .append(Short.TYPE, (short)0)
+ .append(Integer.TYPE, 0)
+ .append(Long.TYPE, 0l)
+ .append(Float.TYPE, 0f)
+ .append(Double.TYPE, 0d)
+ .append(Byte.TYPE, (byte)0)
+ .append(Boolean.class, false)
+ .append(Character.class, (char)0)
+ .append(Short.class, (short)0)
+ .append(Integer.class, 0)
+ .append(Long.class, 0l)
+ .append(Float.class, 0f)
+ .append(Double.class, 0d)
+ .append(Byte.class, (byte)0)
+ );
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
index 97cd3be..0169033 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
@@ -55,7 +55,7 @@ public @interface RemoteMethod {
String path() default "";
/**
- * Defines whether to use <code>GET</code> or <code>POST</code> for REST calls.
+ * Defines the HTTP method to use for REST calls.
* <p>
* Possible values:
* <ul>
@@ -66,4 +66,31 @@ public @interface RemoteMethod {
* The default value is <js>"POST"</js>.
*/
String httpMethod() default "POST";
+
+ /**
+ * The value the remoteable method returns.
+ * <p>
+ * Possible values:
+ * <ul>
+ * <li>{@link ReturnValue#BODY} (default) - The body of the HTTP response converted to a POJO.
+ * <br>The return type on the Java method can be any of the following:
+ * <ul>
+ * <li><jk>void</jk> - Don't parse any response. Note that the method will still throw an exception if an
+ * error HTTP status is returned.
+ * <li>Any parsable POJO - The body of the response will be converted to the POJO using the parser defined
+ * on the <code>RestClient</code>.
+ * <li><code>HttpResponse</code> - Returns the raw <code>HttpResponse</code> returned by the inner
+ * <code>HttpClient</code>.
+ * <li>{@link Reader} - Returns access to the raw reader of the response.
+ * <li>{@link InputStream} - Returns access to the raw input stream of the response.
+ * </ul>
+ * <li>{@link ReturnValue#HTTP_STATUS} - The HTTP status code on the response.
+ * <br>The return type on the Java method can be any of the following:
+ * <ul>
+ * <li><jk>int</jk>/<code>Integer</code> - The HTTP response code.
+ * <li><jk>boolean</jk>/<code>Boolean</code> - <jk>true</jk> if the response code is <code><400</code>
+ * </ul>
+ * </ul>
+ */
+ ReturnValue returns() default ReturnValue.BODY;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
index 8430ae8..2db986e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
@@ -37,6 +37,7 @@ public class RemoteableMethodMeta {
private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, formDataArgs, requestBeanArgs;
private final Integer[] otherArgs;
private final Integer bodyArg;
+ private final ReturnValue returnValue;
/**
* Constructor.
@@ -55,6 +56,7 @@ public class RemoteableMethodMeta {
this.requestBeanArgs = b.requestBeanArgs.toArray(new RemoteMethodArg[b.requestBeanArgs.size()]);
this.otherArgs = b.otherArgs.toArray(new Integer[b.otherArgs.size()]);
this.bodyArg = b.bodyArg;
+ this.returnValue = b.returnValue;
}
private static class Builder {
@@ -68,6 +70,7 @@ public class RemoteableMethodMeta {
private List<Integer>
otherArgs = new LinkedList<Integer>();
private Integer bodyArg;
+ private ReturnValue returnValue;
private Builder(String restUrl, Method m) {
Remoteable r = m.getDeclaringClass().getAnnotation(Remoteable.class);
@@ -83,6 +86,8 @@ public class RemoteableMethodMeta {
if (! isOneOf(methodPaths, "NAME", "SIGNATURE"))
throw new RemoteableMetadataException(m, "Invalid value specified for @Remoteable.methodPaths() annotation. Valid values are [NAME,SIGNATURE].");
+ returnValue = rm == null ? ReturnValue.BODY : rm.returns();
+
url =
trimSlashes(restUrl)
+ '/'
@@ -206,4 +211,12 @@ public class RemoteableMethodMeta {
public Integer getBodyArg() {
return bodyArg;
}
+
+ /**
+ * Returns whether the method returns the HTTP response body or status code.
+ * @return Whether the method returns the HTTP response body or status code.
+ */
+ public ReturnValue getReturns() {
+ return returnValue;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-core/src/main/java/org/apache/juneau/remoteable/ReturnValue.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/ReturnValue.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/ReturnValue.java
new file mode 100644
index 0000000..a6ebc3e
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/ReturnValue.java
@@ -0,0 +1,25 @@
+// ***************************************************************************************************************************
+// * 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.remoteable;
+
+/**
+ * Possible values for the {@link RemoteMethod#returns()} annotation.
+ */
+public enum ReturnValue {
+
+ /** HTTP response body */
+ BODY,
+
+ /** HTTP status code */
+ HTTP_STATUS;
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java b/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
index 737fb32..17292ef 100644
--- a/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
+++ b/juneau-core/src/main/java/org/apache/juneau/utils/PojoQuery.java
@@ -238,6 +238,7 @@ public final class PojoQuery {
int limit = args.getLimit();
if (pos != 0 || limit != 0) {
int end = (limit == 0 || limit+pos >= l.size()) ? l.size() : limit + pos;
+ pos = Math.min(pos, l.size());
ObjectList l2 = new DelegateList(((DelegateList)l).getClassMeta());
l2.addAll(l.subList(pos, end));
l = l2;
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/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 12d6c29..15aa1eb 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6183,6 +6183,7 @@
<li>{@link org.apache.juneau.utils.PojoQuery} improvements.
<br>Search columns containing lists and maps.
<br>Sort columns containing lists and maps.
+ <li>New {@link org.apache.juneau.remoteable.RemoteMethod#returns()} annotation.
</ul>
<h6 class='topic'>org.apache.juneau.rest</h6>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/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 484d934..6d06825 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
@@ -30,6 +30,7 @@ import org.apache.http.client.utils.*;
import org.apache.http.entity.*;
import org.apache.http.impl.client.*;
import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.remoteable.*;
@@ -642,7 +643,21 @@ public class RestClient extends CoreObject {
rc.input(otherArgs);
}
- return rc.getResponse(method.getGenericReturnType());
+ if (rmm.getReturns() == ReturnValue.HTTP_STATUS) {
+ rc.ignoreErrors();
+ int returnCode = rc.run();
+ Class<?> rt = method.getReturnType();
+ if (rt == Integer.class || rt == int.class)
+ return returnCode;
+ if (rt == Boolean.class || rt == boolean.class)
+ return returnCode < 400;
+ throw new RestCallException("Invalid return type on method annotated with @RemoteableMethod(returns=HTTP_STATUS). Only integer and booleans types are valid.");
+ }
+
+ Object v = rc.getResponse(method.getGenericReturnType());
+ if (v == null && method.getReturnType().isPrimitive())
+ v = ClassUtils.getPrimitiveDefault(method.getReturnType());
+ return v;
} catch (RestCallException e) {
// Try to throw original exception if possible.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
index d613422..157e20d 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
import java.util.*;
import org.apache.juneau.microservice.*;
+import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.test.pojos.*;
import org.apache.juneau.utils.*;
@@ -1720,4 +1721,17 @@ public class ThirdPartyProxyResource extends ResourceJena {
return "OK";
}
+ //--------------------------------------------------------------------------------
+ // @RemoteableMethod(returns=HTTP_STATUS)
+ //--------------------------------------------------------------------------------
+
+ @RestMethod(name="GET", path="/httpStatusReturn200")
+ public void httpStatusReturn200(RestResponse res) {
+ res.setStatus(200);
+ }
+
+ @RestMethod(name="GET", path="/httpStatusReturn404")
+ public void httpStatusReturn404(RestResponse res) {
+ res.setStatus(404);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
index fe02c60..b6c0e5b 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
@@ -2147,6 +2147,55 @@ public class ThirdPartyProxyTest extends RestTestcase {
assertEquals("OK", r);
}
+ //--------------------------------------------------------------------------------
+ // @RemoteableMethod(returns=HTTP_STATUS)
+ //--------------------------------------------------------------------------------
+ @Test
+ public void i01a() throws Exception {
+ int r = proxy.httpStatusReturnInt200();
+ assertEquals(200, r);
+ }
+
+ @Test
+ public void i01b() throws Exception {
+ Integer r = proxy.httpStatusReturnInteger200();
+ assertEquals(200, r.intValue());
+ }
+
+ @Test
+ public void i01c() throws Exception {
+ int r = proxy.httpStatusReturnInt404();
+ assertEquals(404, r);
+ }
+
+ @Test
+ public void i01d() throws Exception {
+ Integer r = proxy.httpStatusReturnInteger404();
+ assertEquals(404, r.intValue());
+ }
+
+ @Test
+ public void i02a() throws Exception {
+ boolean r = proxy.httpStatusReturnBool200();
+ assertEquals(true, r);
+ }
+
+ @Test
+ public void i02b() throws Exception {
+ Boolean r = proxy.httpStatusReturnBoolean200();
+ assertEquals(true, r);
+ }
+
+ @Test
+ public void i02c() throws Exception {
+ boolean r = proxy.httpStatusReturnBool404();
+ assertEquals(false, r);
+ }
+
+ public void i02d() throws Exception {
+ Boolean r = proxy.httpStatusReturnBoolean404();
+ assertEquals(false, r);
+ }
//--------------------------------------------------------------------------------
// Proxy class
@@ -3716,6 +3765,32 @@ public class ThirdPartyProxyTest extends RestTestcase {
@RemoteMethod(httpMethod="POST", path="/setEnum1d3dListMap")
void setEnum1d3dListMap(@Body Map<TestEnum,List<TestEnum[][][]>> x);
+
+ // Method returns status code
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn200", returns=ReturnValue.HTTP_STATUS)
+ int httpStatusReturnInt200();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn200", returns=ReturnValue.HTTP_STATUS)
+ Integer httpStatusReturnInteger200();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn404", returns=ReturnValue.HTTP_STATUS)
+ int httpStatusReturnInt404();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn404", returns=ReturnValue.HTTP_STATUS)
+ Integer httpStatusReturnInteger404();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn200", returns=ReturnValue.HTTP_STATUS)
+ boolean httpStatusReturnBool200();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn200", returns=ReturnValue.HTTP_STATUS)
+ Boolean httpStatusReturnBoolean200();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn404", returns=ReturnValue.HTTP_STATUS)
+ boolean httpStatusReturnBool404();
+
+ @RemoteMethod(httpMethod="GET", path="/httpStatusReturn404", returns=ReturnValue.HTTP_STATUS)
+ Boolean httpStatusReturnBoolean404();
}
// Bean for testing NE annotations.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/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 2563442..207e312 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
@@ -811,7 +811,7 @@ class CallMethod implements Comparable<CallMethod> {
throw new RestException(SC_BAD_REQUEST,
"Invalid argument type passed to the following method: ''{0}''.\n\tArgument types: {1}",
method.toString(), getReadableClassNames(args)
- );
+ ).initCause(e);
} catch (InvocationTargetException e) {
Throwable e2 = e.getTargetException(); // Get the throwable thrown from the doX() method.
if (e2 instanceof RestException)
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/35cb8461/juneau-rest/src/main/resources/org/apache/juneau/rest/widget/QueryWidget.html
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/resources/org/apache/juneau/rest/widget/QueryWidget.html b/juneau-rest/src/main/resources/org/apache/juneau/rest/widget/QueryWidget.html
index 02c4adf..d89516f 100644
--- a/juneau-rest/src/main/resources/org/apache/juneau/rest/widget/QueryWidget.html
+++ b/juneau-rest/src/main/resources/org/apache/juneau/rest/widget/QueryWidget.html
@@ -63,71 +63,109 @@
.tooltiptext {
white-space: nowrap;
float: left;
+ border: 1px solid black;
}
</style>
<form id='queryForm' style='display:inline'>
<table id='query' class='queryInput hidden'>
<tr>
- <th>
+ <th>Search:</th>
+ <td>
+ <input name="s" size="50" value='$R{query.s}'>
+ </td>
+ <td>
<div class="tooltip">
- Search <small>(?)</small>:
+ <small>(?)</small>
<span class="tooltiptext">
Comma-delimited list of key/value pair search terms.
- <br>Keys are column names.
- <br>Values are search terms.
- <br>Refer to the <code>Queryable</code> javadocs for a full explanation of possible search terms.
- <br>Example: <code>column1=foo*, column2<100, column3=2013-2016.06.30</code>
+ <br>
+ <br>Keys are column names. Values are search terms.
+ <br>
+ <br><b>Example:</b> <code>[column1=foo*, column2<100, column3=2013-2016.06.30]</code>
+ <br>
+ <br><b>String fields:</b>
+ <br> - <code>'*'</code> represents any character
+ <br> - <code>'?'</code> represents one character
+ <br> - Use single or double quotes for phrases
+ <br> e.g. <code>[column='foo bar']</code> - The term 'foo bar'
+ <br> - Multiple search terms are ORed
+ <br> e.g. <code>[column=foo bar]</code> - 'foo' OR 'bar'
+ <br> - Prepend <code>'+'</code> on tokens that must match
+ <br> e.g. <code>[column=+foo* +*bar]</code> - Start with 'foo' AND end with 'bar'.
+ <br> - Prepend <code>'-'</code> on tokens that must not match
+ <br> e.g. <code>[column=+foo* -*bar]</code> - Start with 'foo' AND does not end with 'bar'.
+ <br>
+ <br><b>Numeric fields:</b>
+ <br><code>[column=123]</code> - A single number
+ <br><code>[column=1 2 3]</code> - Multiple numbers
+ <br><code>[column=1-100]</code> - Between two numbers
+ <br><code>[column=1-100 200-300]</code> - Two ranges of numbers
+ <br><code>[column>100]</code> - Greater than a number
+ <br><code>[column>=100]</code> - Greater than or equal to a number
+ <br><code>[column=!123]</code> - Not a specific number
+ <br>
+ <br><b>Date/Calendar fields:</b>
+ <br><code>[column=2001]</code> - A specific year
+ <br><code>[column=2001.01.01.10.50]</code> - A specific time
+ <br><code>[column=>2001]</code> - After a specific year
+ <br><code>[column=>=2001]</code> - During or after a specific year
+ <br><code>[column=2001-2003.06.30]</code> - A date range
+ <br><code>[column=2001 2003 2005]</code> - Multiple ORed dates
</span>
</div>
- </th>
- <td>
- <input name="s" size="50" value='$R{query.s}'>
</td>
</tr>
<tr>
- <th>
+ <th>View:</th>
+ <td>
+ <input name="v" size="50" value='$R{query.v}'>
+ </td>
+ <td>
<div class="tooltip">
- View <small>(?)</small>:
+ <small>(?)</small>
<span class="tooltiptext">
Comma-delimited list of columns to display.
- <br>Example: <code>column1, column2</code>
+ <br>
+ <br><b>Example:</b> <code>[column1, column2]</code>
</span>
</div>
- </th>
- <td>
- <input name="v" size="50" value='$R{query.v}'>
</td>
</tr>
<tr>
- <th>
+ <th>Sort:</th>
+ <td>
+ <input name="o" size="50" value='$R{query.o}'>
+ </td>
+ <td>
<div class="tooltip">
- Sort <small>(?)</small>:
+ <small>(?)</small>
<span class="tooltiptext">
Comma-delimited list of columns to sort by.
<br>Columns can be suffixed with '-' to indicate descending order.
- <br>Example: <code>column1, column2-</code>
+ <br>
+ <br><b>Example:</b> <code>[column1, column2-]</code>
+ <br>
+ <br><b>Notes:</b>
+ <br> - Columns containing collections/arrays/lists are sorted by size.
</span>
</div>
- </th>
- <td>
- <input name="o" size="50" value='$R{query.o}'>
</td>
</tr>
<tr>
- <th>
- Page:
- </th>
+ <th>Page:</th>
<td>
Position: <input name='p' type='number' style='width:50px' step=20 min=0 value='$R{query.p}'>
Limit: <input name='l' type='number' style='width:50px' step=20 min=0 value='$R{query.l}'>
- Ignore-case: <input name='i' type='checkbox' value='true'>
+ <span style='float:right'>Ignore-case: <input name='i' type='checkbox' value='true'></span>
</td>
- </tr>
+ <td>
+ </td>
+ </tr>
<tr>
<th>
</th>
- <td style='float:right'>
+ <td colspan='2' style='text-align:right'>
<input type='reset' value='Reset'>
<input type='button' value='Cancel' onclick='getElementById("query").classList.add("hidden")'>
<input type="submit" value='Submit'>