Repository: incubator-juneau Updated Branches: refs/heads/master b983a7f62 -> c68cc34d5
Add default values for @Header/@Query/@FormData annotations. Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/c68cc34d Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/c68cc34d Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/c68cc34d Branch: refs/heads/master Commit: c68cc34d5dd2d04811f65e8371207554360571ca Parents: b983a7f Author: JamesBognar <[email protected]> Authored: Fri May 12 17:25:51 2017 -0400 Committer: JamesBognar <[email protected]> Committed: Fri May 12 17:25:51 2017 -0400 ---------------------------------------------------------------------- juneau-core/src/main/javadoc/overview.html | 11 ++++ .../juneau/rest/test/FormDataResource.java | 37 ++++++++++++ .../juneau/rest/test/HeadersResource.java | 55 ++++++++++++++++- .../apache/juneau/rest/test/QueryResource.java | 63 ++++++++++++++++++++ .../java/org/apache/juneau/rest/test/Root.java | 1 + .../apache/juneau/rest/test/FormDataTest.java | 35 +++++++++++ .../apache/juneau/rest/test/HeadersTest.java | 48 +++++++++++++++ .../org/apache/juneau/rest/test/QueryTest.java | 60 +++++++++++++++++++ .../org/apache/juneau/rest/test/_TestSuite.java | 1 + .../java/org/apache/juneau/rest/CallMethod.java | 51 ++++++++++++++-- .../org/apache/juneau/rest/RequestFormData.java | 20 +++++++ .../org/apache/juneau/rest/RequestQuery.java | 20 +++++++ .../org/apache/juneau/rest/RestRequest.java | 13 +++- .../java/org/apache/juneau/rest/RestUtils.java | 17 ++++++ .../apache/juneau/rest/annotation/FormData.java | 5 ++ .../apache/juneau/rest/annotation/Header.java | 5 ++ .../apache/juneau/rest/annotation/Query.java | 5 ++ .../juneau/rest/annotation/RestMethod.java | 43 +++++++++++++ 18 files changed, 480 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 f47b431..62ed843 100644 --- a/juneau-core/src/main/javadoc/overview.html +++ b/juneau-core/src/main/javadoc/overview.html @@ -6085,6 +6085,17 @@ that allows you to define your own custom Java method parameter resolvers. <li>Fixed bug where Writer returned by {@link org.apache.juneau.rest.RestResponse#getWriter()} was not being flushed automatically at the end of the HTTP call. + <li>New anntotations added to {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}: + <ul> + <li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultQuery defaultQuery()} + <li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultFormData defaultFormData()} + </ul> + <li>Default values on header, query, and form-data annotations: + <ul> + <li>{@link org.apache.juneau.rest.annotation.Header#def @Header.def()} - Default header value. + <li>{@link org.apache.juneau.rest.annotation.Query#def @Query.def()} - Default query parameter value. + <li>{@link org.apache.juneau.rest.annotation.FormData#def @FormData.def()} - Default form data parameter value. + </ul> </ul> <h6 class='topic'>org.apache.juneau.rest.client</h6> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/FormDataResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/FormDataResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/FormDataResource.java index 3bced3f..3b4cdd1 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/FormDataResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/FormDataResource.java @@ -14,6 +14,7 @@ package org.apache.juneau.rest.test; import java.io.*; +import org.apache.juneau.*; import org.apache.juneau.internal.*; import org.apache.juneau.rest.*; import org.apache.juneau.rest.annotation.*; @@ -34,4 +35,40 @@ public class FormDataResource extends RestServletDefault { public Reader test(RestRequest req) throws IOException { return new StringReader("Content-Type=["+req.getContentType()+"], contents=["+IOUtils.read(req.getReader())+"]"); } + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @RestMethod(name="POST", path="/defaultFormData", defaultFormData={"f1:1","f2=2"," f3 : 3 "}) + public ObjectMap defaultFormData(RequestFormData formData) { + return new ObjectMap() + .append("f1", formData.getFirst("f1")) + .append("f2", formData.getFirst("f2")) + .append("f3", formData.getFirst("f3")); + } + + @RestMethod(name="POST", path="/annotatedFormData") + public ObjectMap annotatedFormData(@FormData("f1") String f1, @FormData("f2") String f2, @FormData("f3") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } + + @RestMethod(name="POST", path="/annotatedFormDataDefault") + public ObjectMap annotatedFormDataDefault(@FormData(value="f1",def="1") String f1, @FormData(value="f2",def="2") String f2, @FormData(value="f3",def="3") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } + + @RestMethod(name="POST", path="/annotatedAndDefaultFormData", defaultFormData={"f1:1","f2=2"," f3 : 3 "}) + public ObjectMap annotatedAndDefaultFormData(@FormData(value="f1",def="4") String f1, @FormData(value="f2",def="5") String f2, @FormData(value="f3",def="6") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java index 0a03469..edb58f2 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java @@ -34,8 +34,9 @@ public class HeadersResource extends RestServlet { private static final long serialVersionUID = 1L; //==================================================================================================== - // Basic tests + // HTTP 1.1 headers //==================================================================================================== + @RestMethod(name="GET", path="/accept") public String accept(Accept accept) { return accept.toString(); @@ -190,4 +191,56 @@ public class HeadersResource extends RestServlet { return new String[]{"*"}; } } + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @RestMethod(name="GET", path="/defaultRequestHeaders", defaultRequestHeaders={"H1:1","H2=2"," H3 : 3 "}) + public ObjectMap defaultRequestHeaders(RequestHeaders headers) { + return new ObjectMap() + .append("h1", headers.getFirst("H1")) + .append("h2", headers.getFirst("H2")) + .append("h3", headers.getFirst("H3")); + } + + @RestMethod(name="GET", path="/defaultRequestHeadersCaseInsensitive", defaultRequestHeaders={"H1:1","H2=2"," H3 : 3 "}) + public ObjectMap defaultRequestHeadersCaseInsensitive(RequestHeaders headers) { + return new ObjectMap() + .append("h1", headers.getFirst("h1")) + .append("h2", headers.getFirst("h2")) + .append("h3", headers.getFirst("h3")); + } + + @RestMethod(name="GET", path="/annotatedHeaders") + public ObjectMap annotatedHeaders(@Header("H1") String h1, @Header("H2") String h2, @Header("H3") String h3) { + return new ObjectMap() + .append("h1", h1) + .append("h2", h2) + .append("h3", h3); + } + + @RestMethod(name="GET", path="/annotatedHeadersCaseInsensitive") + public ObjectMap annotatedHeadersCaseInsensitive(@Header("h1") String h1, @Header("h2") String h2, @Header("h3") String h3) { + return new ObjectMap() + .append("h1", h1) + .append("h2", h2) + .append("h3", h3); + } + + @RestMethod(name="GET", path="/annotatedHeadersDefault") + public ObjectMap annotatedHeadersDefault(@Header(value="h1",def="1") String h1, @Header(value="h2",def="2") String h2, @Header(value="h3",def="3") String h3) { + return new ObjectMap() + .append("h1", h1) + .append("h2", h2) + .append("h3", h3); + } + + @RestMethod(name="GET", path="/annotatedAndDefaultHeaders", defaultRequestHeaders={"H1:1","H2=2"," H3 : 3 "}) + public ObjectMap annotatedAndDefaultHeaders(@Header(value="h1",def="4") String h1, @Header(value="h2",def="5") String h2, @Header(value="h3",def="6") String h3) { + return new ObjectMap() + .append("h1", h1) + .append("h2", h2) + .append("h3", h3); + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/QueryResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/QueryResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/QueryResource.java new file mode 100644 index 0000000..4c33538 --- /dev/null +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/QueryResource.java @@ -0,0 +1,63 @@ +// *************************************************************************************************************************** +// * 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 org.apache.juneau.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.rest.annotation.*; + +/** + * JUnit automated testcase resource. + */ +@RestResource( + path="/testQuery" +) +public class QueryResource extends RestServletDefault { + private static final long serialVersionUID = 1L; + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @RestMethod(name="GET", path="/defaultQuery", defaultQuery={"f1:1","f2=2"," f3 : 3 "}) + public ObjectMap defaultQuery(RequestQuery query) { + return new ObjectMap() + .append("f1", query.getFirst("f1")) + .append("f2", query.getFirst("f2")) + .append("f3", query.getFirst("f3")); + } + + @RestMethod(name="GET", path="/annotatedQuery") + public ObjectMap annotatedQuery(@Query("f1") String f1, @Query("f2") String f2, @Query("f3") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } + + @RestMethod(name="GET", path="/annotatedQueryDefault") + public ObjectMap annotatedQueryDefault(@Query(value="f1",def="1") String f1, @Query(value="f2",def="2") String f2, @Query(value="f3",def="3") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } + + @RestMethod(name="GET", path="/annotatedAndDefaultQuery", defaultQuery={"f1:1","f2=2"," f3 : 3 "}) + public ObjectMap annotatedAndDefaultQuery(@Query(value="f1",def="4") String f1, @Query(value="f2",def="5") String f2, @Query(value="f3",def="6") String f3) { + return new ObjectMap() + .append("f1", f1) + .append("f2", f2) + .append("f3", f3); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 f6846eb..f04181b 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 @@ -59,6 +59,7 @@ import org.apache.juneau.rest.labels.*; PathsResource.class, PathVariablesResource.class, PropertiesResource.class, + QueryResource.class, RestClient2Resource.class, SerializersResource.class, StaticFilesResource.class, http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java index a8695a3..9aeff98 100644 --- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java +++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java @@ -12,10 +12,12 @@ // *************************************************************************************************************************** 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.*; import org.apache.juneau.rest.client.*; import org.apache.juneau.urlencoding.*; import org.apache.juneau.utils.*; @@ -27,6 +29,7 @@ import org.junit.*; public class FormDataTest extends RestTestcase { private static String URL = "/testFormData"; + RestClient client = TestMicroservice.DEFAULT_CLIENT; //==================================================================================================== // Form data tests using RestCall.formData() method. @@ -97,4 +100,36 @@ public class FormDataTest extends RestTestcase { .getResponseAsString(); assertEquals("Content-Type=[application/x-www-form-urlencoded], contents=[foo=foo&%27foo%27=%27foo%27&%28foo%29=%28foo%29&%40%28foo%29=%40%28foo%29]", r); } + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @Test + public void defaultFormData() throws Exception { + assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doPost(URL + "/defaultFormData").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/defaultFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/defaultFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedFormData() throws Exception { + assertObjectEquals("{f1:null,f2:null,f3:null}", client.doPost(URL + "/annotatedFormData").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/annotatedFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/annotatedFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedFormDataDefault() throws Exception { + assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doPost(URL + "/annotatedFormDataDefault").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/annotatedFormDataDefault").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/annotatedFormDataDefault").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedAndDefaultFormData() throws Exception { + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL + "/annotatedAndDefaultFormData").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doPost(URL + "/annotatedAndDefaultFormData").formData("f1",7).formData("f2",8).formData("f3",9).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doPost(URL + "/annotatedAndDefaultFormData").formData("f1",7).formData("f2",8).formData("f3",9).getResponse(ObjectMap.class)); + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HeadersTest.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HeadersTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HeadersTest.java index a834210..82a4d05 100644 --- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HeadersTest.java +++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/HeadersTest.java @@ -12,8 +12,10 @@ // *************************************************************************************************************************** package org.apache.juneau.rest.test; +import static org.apache.juneau.rest.test.TestUtils.*; import static org.junit.Assert.*; +import org.apache.juneau.*; import org.apache.juneau.rest.client.*; import org.junit.*; @@ -210,4 +212,50 @@ public class HeadersTest extends RestTestcase { assertEquals("foo", client.doGet(URL + "/customHeader").header("Custom", "foo").getResponseAsString()); assertEquals("foo", client.doGet(URL + "/customHeader").query("Custom", "foo").getResponseAsString()); } + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @Test + public void defaultRequestHeaders() throws Exception { + assertObjectEquals("{h1:'1',h2:'2',h3:'3'}", client.doGet(URL + "/defaultRequestHeaders").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/defaultRequestHeaders").header("H1",4).header("H2",5).header("H3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/defaultRequestHeaders").header("h1",4).header("h2",5).header("h3",6).getResponse(ObjectMap.class)); + } + + @Test + public void defaultRequestHeadersCaseInsensitive() throws Exception { + assertObjectEquals("{h1:'1',h2:'2',h3:'3'}", client.doGet(URL + "/defaultRequestHeadersCaseInsensitive").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/defaultRequestHeadersCaseInsensitive").header("H1",4).header("H2",5).header("H3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/defaultRequestHeadersCaseInsensitive").header("h1",4).header("h2",5).header("h3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedHeaders() throws Exception { + assertObjectEquals("{h1:null,h2:null,h3:null}", client.doGet(URL + "/annotatedHeaders").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeaders").header("H1",4).header("H2",5).header("H3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeaders").header("h1",4).header("h2",5).header("h3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedHeadersCaseInsensitive() throws Exception { + assertObjectEquals("{h1:null,h2:null,h3:null}", client.doGet(URL + "/annotatedHeadersCaseInsensitive").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeadersCaseInsensitive").header("H1",4).header("H2",5).header("H3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeadersCaseInsensitive").header("h1",4).header("h2",5).header("h3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedHeadersDefault() throws Exception { + assertObjectEquals("{h1:'1',h2:'2',h3:'3'}", client.doGet(URL + "/annotatedHeadersDefault").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeadersDefault").header("H1",4).header("H2",5).header("H3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedHeadersDefault").header("h1",4).header("h2",5).header("h3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedAndDefaultHeaders() throws Exception { + assertObjectEquals("{h1:'4',h2:'5',h3:'6'}", client.doGet(URL + "/annotatedAndDefaultHeaders").getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'7',h2:'8',h3:'9'}", client.doGet(URL + "/annotatedAndDefaultHeaders").header("H1",7).header("H2",8).header("H3",9).getResponse(ObjectMap.class)); + assertObjectEquals("{h1:'7',h2:'8',h3:'9'}", client.doGet(URL + "/annotatedAndDefaultHeaders").header("h1",7).header("h2",8).header("h3",9).getResponse(ObjectMap.class)); + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/QueryTest.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/QueryTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/QueryTest.java new file mode 100644 index 0000000..c211ca8 --- /dev/null +++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/QueryTest.java @@ -0,0 +1,60 @@ +// *************************************************************************************************************************** +// * 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 org.apache.juneau.*; +import org.apache.juneau.rest.client.*; +import org.junit.*; + +/** + * Tests client-side form posts. + */ +public class QueryTest extends RestTestcase { + + private static String URL = "/testQuery"; + RestClient client = TestMicroservice.DEFAULT_CLIENT; + + //==================================================================================================== + // Default values. + //==================================================================================================== + + @Test + public void defaultQuery() throws Exception { + assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doGet(URL + "/defaultQuery").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/defaultQuery").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/defaultQuery").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedQuery() throws Exception { + assertObjectEquals("{f1:null,f2:null,f3:null}", client.doGet(URL + "/annotatedQuery").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/annotatedQuery").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/annotatedQuery").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedQueryDefault() throws Exception { + assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doGet(URL + "/annotatedQueryDefault").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/annotatedQueryDefault").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/annotatedQueryDefault").query("f1",4).query("f2",5).query("f3",6).getResponse(ObjectMap.class)); + } + + @Test + public void annotatedAndDefaultQuery() throws Exception { + assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doGet(URL + "/annotatedAndDefaultQuery").getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doGet(URL + "/annotatedAndDefaultQuery").query("f1",7).query("f2",8).query("f3",9).getResponse(ObjectMap.class)); + assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doGet(URL + "/annotatedAndDefaultQuery").query("f1",7).query("f2",8).query("f3",9).getResponse(ObjectMap.class)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 dfb0c54..d8a0b1b 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 @@ -55,6 +55,7 @@ import org.junit.runners.Suite.*; PathsTest.class, PathTest.class, PropertiesTest.class, + QueryTest.class, RestClientTest.class, RestUtilsTest.class, SerializersTest.class, http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 869684c..5f5cc6a 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 @@ -18,6 +18,7 @@ import static org.apache.juneau.rest.RestContext.*; import static org.apache.juneau.rest.annotation.Inherit.*; import static org.apache.juneau.serializer.SerializerContext.*; +import java.lang.annotation.*; import java.lang.reflect.*; import java.lang.reflect.Method; import java.util.*; @@ -55,7 +56,7 @@ class CallMethod implements Comparable<CallMethod> { private final UrlEncodingParser urlEncodingParser; private final UrlEncodingSerializer urlEncodingSerializer; private final ObjectMap properties; - private final Map<String,String> defaultRequestHeaders; + private final Map<String,String> defaultRequestHeaders, defaultQuery, defaultFormData; private final String defaultCharset; private final boolean deprecated; private final String description, tags, summary, externalDocs; @@ -83,6 +84,8 @@ class CallMethod implements Comparable<CallMethod> { this.urlEncodingSerializer = b.urlEncodingSerializer; this.properties = b.properties; this.defaultRequestHeaders = b.defaultRequestHeaders; + this.defaultQuery = b.defaultQuery; + this.defaultFormData = b.defaultFormData; this.defaultCharset = b.defaultCharset; this.deprecated = b.deprecated; this.description = b.description; @@ -110,7 +113,7 @@ class CallMethod implements Comparable<CallMethod> { private UrlEncodingParser urlEncodingParser; private UrlEncodingSerializer urlEncodingSerializer; private ObjectMap properties; - private Map<String,String> defaultRequestHeaders; + private Map<String,String> defaultRequestHeaders, defaultQuery, defaultFormData; private boolean plainParams, deprecated; private Integer priority; private org.apache.juneau.rest.annotation.Parameter[] parameters; @@ -261,12 +264,48 @@ class CallMethod implements Comparable<CallMethod> { defaultRequestHeaders = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER); for (String s : m.defaultRequestHeaders()) { - String[] h = RestUtils.parseHeader(s); + String[] h = RestUtils.parseKeyValuePair(s); if (h == null) - throw new RestServletException("Invalid default request header specified: ''{0}''. Must be in the format: ''Header-Name: header-value''", s); + throw new RestServletException("Invalid default request header specified: ''{0}''. Must be in the format: ''name[:=]value''", s); defaultRequestHeaders.put(h[0], h[1]); } + defaultQuery = new LinkedHashMap<String,String>(); + for (String s : m.defaultQuery()) { + String[] h = RestUtils.parseKeyValuePair(s); + if (h == null) + throw new RestServletException("Invalid default query parameter specified: ''{0}''. Must be in the format: ''name[:=]value''", s); + defaultQuery.put(h[0], h[1]); + } + + defaultFormData = new LinkedHashMap<String,String>(); + for (String s : m.defaultFormData()) { + String[] h = RestUtils.parseKeyValuePair(s); + if (h == null) + throw new RestServletException("Invalid default form data parameter specified: ''{0}''. Must be in the format: ''name[:=]value''", s); + defaultFormData.put(h[0], h[1]); + } + + Type[] pt = method.getGenericParameterTypes(); + Annotation[][] pa = method.getParameterAnnotations(); + for (int i = 0; i < pt.length; i++) { + for (Annotation a : pa[i]) { + if (a instanceof Header) { + Header h = (Header)a; + if (! h.def().isEmpty()) + defaultRequestHeaders.put(h.value(), h.def()); + } else if (a instanceof Query) { + Query q = (Query)a; + if (! q.def().isEmpty()) + defaultQuery.put(q.value(), q.def()); + } else if (a instanceof FormData) { + FormData f = (FormData)a; + if (! f.def().isEmpty()) + defaultFormData.put(f.value(), f.def()); + } + } + } + defaultCharset = properties.getString(REST_defaultCharset, context.getDefaultCharset()); String paramFormat = properties.getString(REST_paramFormat, context.getParamFormat()); plainParams = paramFormat.equals("PLAIN"); @@ -660,9 +699,9 @@ class CallMethod implements Comparable<CallMethod> { for (int i = 0; i < pathPattern.getVars().length; i++) req.getPathMatch().put(pathPattern.getVars()[i], patternVals[i]); req.getPathMatch().setRemainder(remainder); - + ObjectMap requestProperties = createRequestProperties(properties, req); - req.init(method, requestProperties, defaultRequestHeaders, defaultCharset, serializers, parsers, urlEncodingParser, encoders, pageTitle, pageText, pageLinks); + req.init(method, requestProperties, defaultRequestHeaders, defaultQuery, defaultFormData, defaultCharset, serializers, parsers, urlEncodingParser, encoders, pageTitle, pageText, pageLinks); res.init(requestProperties, defaultCharset, serializers, urlEncodingSerializer, encoders); // Class-level guards http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java index 12d2157..824181c 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java @@ -41,6 +41,26 @@ public class RequestFormData extends LinkedHashMap<String,String[]> { } /** + * Adds default entries to these form-data parameters. + * <p> + * This includes the default form-data parameters defined on the servlet and method levels. + * + * @param defaultEntries The default entries. Can be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestFormData addDefault(Map<String,String> defaultEntries) { + if (defaultEntries != null) { + for (Map.Entry<String,String> e : defaultEntries.entrySet()) { + String key = e.getKey(), value = e.getValue(); + String[] v = get(key); + if (v == null) + put(key, new String[]{value}); + } + } + return this; + } + + /** * Sets a request form data parameter value. * * @param name The parameter name. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java index 6a9a564..1a9b758 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java @@ -43,6 +43,26 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> { } /** + * Adds default entries to these query parameters. + * <p> + * This includes the default queries defined on the servlet and method levels. + * + * @param defaultEntries The default entries. Can be <jk>null</jk>. + * @return This object (for method chaining). + */ + public RequestQuery addDefault(Map<String,String> defaultEntries) { + if (defaultEntries != null) { + for (Map.Entry<String,String> e : defaultEntries.entrySet()) { + String key = e.getKey(), value = e.getValue(); + String[] v = get(key); + if (v == null) + put(key, new String[]{value}); + } + } + return this; + } + + /** * Sets a request query parameter value. * * @param name The parameter name. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 774fb5c..b4b60ca 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 @@ -78,6 +78,7 @@ public final class RestRequest extends HttpServletRequestWrapper { private VarResolverSession varSession; private final RequestQuery queryParams; private RequestFormData formData; + private Map<String,String> defFormData; private RequestPathMatch pathParams; private boolean isPost; private String servletURI, relativeServletURI; @@ -150,7 +151,10 @@ public final class RestRequest extends HttpServletRequestWrapper { * Called from RestServlet after a match has been made but before the guard or method invocation. */ @SuppressWarnings("hiding") - final void init(Method javaMethod, ObjectMap properties, Map<String,String> mDefaultRequestHeaders, String defaultCharset, SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser mUrlEncodingParser, EncoderGroup encoders, String pageTitle, String pageText, String pageLinks) { + final void init(Method javaMethod, ObjectMap properties, Map<String,String> defHeader, + Map<String,String> defQuery, Map<String,String> defFormData, String defaultCharset, + SerializerGroup mSerializers, ParserGroup mParsers, UrlEncodingParser mUrlEncodingParser, + EncoderGroup encoders, String pageTitle, String pageText, String pageLinks) { this.javaMethod = javaMethod; this.properties = properties; this.urlEncodingParser = mUrlEncodingParser; @@ -159,10 +163,11 @@ public final class RestRequest extends HttpServletRequestWrapper { .setParser(urlEncodingParser) .setBeanSession(beanSession); this.queryParams + .addDefault(defQuery) .setParser(urlEncodingParser) .setBeanSession(beanSession); this.headers - .addDefault(mDefaultRequestHeaders) + .addDefault(defHeader) .addDefault(context.getDefaultRequestHeaders()) .setParser(urlEncodingParser) .setBeanSession(beanSession); @@ -178,6 +183,7 @@ public final class RestRequest extends HttpServletRequestWrapper { this.pageTitle = pageTitle; this.pageText = pageText; this.pageLinks = pageLinks; + this.defFormData = defFormData; if (debug) { String msg = "" @@ -366,6 +372,7 @@ public final class RestRequest extends HttpServletRequestWrapper { } } } + formData.addDefault(defFormData); return formData; } catch (Exception e) { throw new RestException(SC_INTERNAL_SERVER_ERROR, e); @@ -381,7 +388,7 @@ public final class RestRequest extends HttpServletRequestWrapper { return getFormData().getFirst(name); } - + //-------------------------------------------------------------------------------- // Path parameters //-------------------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/RestUtils.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestUtils.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestUtils.java index 73a89a9..f39a2ff 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestUtils.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestUtils.java @@ -163,4 +163,21 @@ public final class RestUtils { String val = s.substring(i+1).trim(); return new String[]{name,val}; } + + /** + * Parses key/value pairs separated by either : or = + */ + static String[] parseKeyValuePair(String s) { + int i = -1; + for (int j = 0; j < s.length() && i < 0; j++) { s.indexOf(':'); + char c = s.charAt(j); + if (c == '=' || c == ':') + i = j; + } + if (i == -1) + return null; + String name = s.substring(0, i).trim(); + String val = s.substring(i+1).trim(); + return new String[]{name,val}; + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/FormData.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/FormData.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/FormData.java index bf40391..bc453aa 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/FormData.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/FormData.java @@ -93,4 +93,9 @@ public @interface FormData { * <js>"foo"</js> when using UON mode. */ String format() default "INHERIT"; + + /** + * The default value for this form-data parameter if it's not present in the request. + */ + String def() default ""; } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Header.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Header.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Header.java index aacc510..876fbf3 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Header.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Header.java @@ -49,4 +49,9 @@ public @interface Header { * HTTP header name. */ String value(); + + /** + * The default value for this header if it's not present in the request. + */ + String def() default ""; } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java index 1f00fdc..d8e3414 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/Query.java @@ -89,4 +89,9 @@ public @interface Query { * <js>"foo"</js> when using UON mode. */ String format() default "INHERIT"; + + /** + * The default value for this query parameter if it's not present in the request. + */ + String def() default ""; } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/c68cc34d/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 fdaa469..b2fa562 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 @@ -289,10 +289,53 @@ public @interface RestMethod { * ... * } * </p> + * <p> + * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter. + * Key and value is trimmed of whitespace. */ String[] defaultRequestHeaders() default {}; /** + * Specifies default values for query parameters. + * <p> + * Strings are of the format <js>"name=value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getQuery(String)} when the parameter is not present on the request. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/*"</js>, defaultQuery={<js>"foo=bar"</js>}) + * <jk>public</jk> String doGet(<ja>@Query</ja>(<js>"foo"</js>) String foo) { + * ... + * } + * </p> + * <p> + * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter. + * Key and value is trimmed of whitespace. + */ + String[] defaultQuery() default {}; + + /** + * Specifies default values for form-data parameters. + * <p> + * Strings are of the format <js>"name=value"</js>. + * <p> + * Affects values returned by {@link RestRequest#getFormData(String)} when the parameter is not present on the request. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode'> + * <ja>@RestMethod</ja>(name=<js>"POST"</js>, path=<js>"/*"</js>, defaultFormData={<js>"foo=bar"</js>}) + * <jk>public</jk> String doGet(<ja>@FormData</ja>(<js>"foo"</js>) String foo) { + * ... + * } + * </p> + * <p> + * You can use either <js>':'</js> or <js>'='</js> as the key/value delimiter. + * Key and value is trimmed of whitespace. + */ + String[] defaultFormData() default {}; + + /** * Optional summary for the exposed API. * <p> * This summary is used in the following locations:
