This is an automated email from the ASF dual-hosted git repository. reta pushed a commit to branch CXF-8174 in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 893f86f79688cd9587fffeed493c33cdd3325d5a Author: reta <[email protected]> AuthorDate: Wed Dec 18 21:35:41 2019 -0500 CXF-8174: Incorrect service method resolution --- .../org/apache/cxf/jaxrs/utils/JAXRSUtils.java | 17 ++++-- .../test/java/org/apache/cxf/jaxrs/BaseApi.java | 39 ++++++++++++++ .../java/org/apache/cxf/jaxrs/BaseRequest.java | 32 +++++++++++ .../java/org/apache/cxf/jaxrs/BaseResponse.java | 32 +++++++++++ .../java/org/apache/cxf/jaxrs/CustomerService.java | 35 ++++++++++++ .../apache/cxf/jaxrs/CustomerServiceRequest.java | 35 ++++++++++++ .../apache/cxf/jaxrs/CustomerServiceResource.java | 29 ++++++++++ .../apache/cxf/jaxrs/CustomerServiceResponse.java | 23 ++++++++ .../java/org/apache/cxf/jaxrs/CustomizedApi.java | 38 +++++++++++++ .../java/org/apache/cxf/jaxrs/GenericService.java | 24 +++++++++ .../cxf/jaxrs/SelectMethodCandidatesTest.java | 63 ++++++++++++++++++++++ 11 files changed, 364 insertions(+), 3 deletions(-) diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java index c6a5209..d1f4daa 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java @@ -719,9 +719,20 @@ public final class JAXRSUtils { int size1 = paraList1.length; int size2 = paraList2.length; for (int i = 0; i < size1 && i < size2; i++) { - int result = paraList1[i].getName().compareTo(paraList2[i].getName()); - if (result != 0) { - return result; + if (!paraList1[i].equals(paraList2[i])) { + // Handling the case when bridge / synthetic methods may be taken + // into account (f.e. when service implements generic interfaces or + // extends the generic classes. + if (paraList1[i].isAssignableFrom(paraList2[i])) { + return 1; + } else if (paraList2[i].isAssignableFrom(paraList1[i])) { + return -1; + } else { + int result = paraList1[i].getName().compareTo(paraList2[i].getName()); + if (result != 0) { + return result; + } + } } } return size1 == size2 ? 0 : size1 < size2 ? -1 : 1; diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseApi.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseApi.java new file mode 100644 index 0000000..63f3d7d --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseApi.java @@ -0,0 +1,39 @@ +/** + * 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.cxf.jaxrs; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +@Path("/api") +public class BaseApi { + @GET + @Produces({ MediaType.APPLICATION_JSON }) + public Response getApi(@Context HttpHeaders headers, @Context UriInfo uriInfo, @PathParam("type") String type) { + return Response.ok().build(); + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseRequest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseRequest.java new file mode 100644 index 0000000..dc0334f --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseRequest.java @@ -0,0 +1,32 @@ +/** + * 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.cxf.jaxrs; + +public class BaseRequest { + private int requestId; + + public int getRequestId() { + return requestId; + } + + public void setRequestId(int requestId) { + this.requestId = requestId; + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseResponse.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseResponse.java new file mode 100644 index 0000000..fbe3a49 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/BaseResponse.java @@ -0,0 +1,32 @@ +/** + * 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.cxf.jaxrs; + +public class BaseResponse { + private int responseId; + + public int getResponseId() { + return responseId; + } + + public void setResponseId(int responseId) { + this.responseId = responseId; + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerService.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerService.java new file mode 100644 index 0000000..17e21d0 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerService.java @@ -0,0 +1,35 @@ +/** + * 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.cxf.jaxrs; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Consumes(MediaType.TEXT_XML) +@Produces(MediaType.TEXT_XML) +public interface CustomerService extends GenericService<CustomerServiceRequest, CustomerServiceResponse> { + @Override + @POST + @Path("process") + CustomerServiceResponse process(CustomerServiceRequest request); +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceRequest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceRequest.java new file mode 100644 index 0000000..40acb14 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceRequest.java @@ -0,0 +1,35 @@ +/** + * 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.cxf.jaxrs; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "CustomerRequest") +public class CustomerServiceRequest extends BaseRequest { + private int customerId; + + public int getCustomerId() { + return customerId; + } + + public void setCustomerId(int customerId) { + this.customerId = customerId; + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResource.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResource.java new file mode 100644 index 0000000..9be79b7 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResource.java @@ -0,0 +1,29 @@ +/** + * 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.cxf.jaxrs; + +public class CustomerServiceResource implements CustomerService { + @Override + public CustomerServiceResponse process(CustomerServiceRequest request) { + CustomerServiceResponse customerServiceResponse = new CustomerServiceResponse(); + customerServiceResponse.setResponseId(request.getRequestId()); + return customerServiceResponse; + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResponse.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResponse.java new file mode 100644 index 0000000..1988a41 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomerServiceResponse.java @@ -0,0 +1,23 @@ +/** + * 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.cxf.jaxrs; + +public class CustomerServiceResponse extends BaseResponse { +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomizedApi.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomizedApi.java new file mode 100644 index 0000000..de9c3f8 --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/CustomizedApi.java @@ -0,0 +1,38 @@ +/** + * 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.cxf.jaxrs; + +import javax.servlet.ServletConfig; +import javax.ws.rs.GET; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +public class CustomizedApi extends BaseApi { + @GET + @Produces({ MediaType.APPLICATION_JSON }) + public Response getApi(@Context ServletConfig config, @Context HttpHeaders headers, @Context UriInfo uriInfo, + @PathParam("type") String type) { + return getApi(headers, uriInfo, type); + } +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/GenericService.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/GenericService.java new file mode 100644 index 0000000..4943cef --- /dev/null +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/GenericService.java @@ -0,0 +1,24 @@ +/** + * 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.cxf.jaxrs; + +public interface GenericService<REQ extends BaseRequest, RES extends BaseResponse> { + RES process(REQ request); +} diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/SelectMethodCandidatesTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/SelectMethodCandidatesTest.java index 946ec80..0a5ea80 100644 --- a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/SelectMethodCandidatesTest.java +++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/SelectMethodCandidatesTest.java @@ -21,19 +21,23 @@ package org.apache.cxf.jaxrs; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; +import javax.servlet.ServletConfig; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.jaxrs.fortest.BookEntity; @@ -158,6 +162,65 @@ public class SelectMethodCandidatesTest { assertNotNull(book); assertEquals("The Book", book.getName()); } + + @Test + public void testFindFromAbstractGenericImpl6() throws Exception { + JAXRSServiceFactoryBean sf = new JAXRSServiceFactoryBean(); + sf.setResourceClasses(CustomerServiceResource.class); + + sf.create(); + List<ClassResourceInfo> resources = ((JAXRSServiceImpl)sf.getService()).getClassResourceInfos(); + Message m = createMessage(); + m.put(Message.CONTENT_TYPE, "text/xml"); + + MetadataMap<String, String> values = new MetadataMap<>(); + OperationResourceInfo ori = findTargetResourceClass(resources, m, + "/process", + "POST", + values, "text/xml", + sortMediaTypes("*/*")); + assertNotNull(ori); + assertEquals("resourceMethod needs to be selected", "process", + ori.getMethodToInvoke().getName()); + + String value = "<CustomerRequest><customerId>1</customerId><requestId>100</requestId></CustomerRequest>"; + m.setContent(InputStream.class, new ByteArrayInputStream(value.getBytes())); + List<Object> params = JAXRSUtils.processParameters(ori, values, m); + assertEquals(1, params.size()); + CustomerServiceRequest request = (CustomerServiceRequest)params.get(0); + assertNotNull(request); + assertEquals(1, request.getCustomerId()); + assertEquals(100, request.getRequestId()); + + final Method notSynthetic = CustomerServiceResource.class.getMethod("process", + new Class[]{CustomerServiceRequest.class}); + assertEquals(notSynthetic, ori.getMethodToInvoke()); + } + + @Test + public void testFindOverridesDifferentArguments() throws Exception { + JAXRSServiceFactoryBean sf = new JAXRSServiceFactoryBean(); + sf.setResourceClasses(CustomizedApi.class); + + sf.create(); + List<ClassResourceInfo> resources = ((JAXRSServiceImpl)sf.getService()).getClassResourceInfos(); + Message m = createMessage(); + m.put(Message.CONTENT_TYPE, "application/json"); + + MetadataMap<String, String> values = new MetadataMap<>(); + OperationResourceInfo ori = findTargetResourceClass(resources, m, + "/api", + "GET", + values, "application/json", + sortMediaTypes("*/*")); + assertNotNull(ori); + assertEquals("resourceMethod needs to be selected", "getApi", + ori.getMethodToInvoke().getName()); + + final Method expected = CustomizedApi.class.getMethod("getApi", + new Class[]{ServletConfig.class, HttpHeaders.class, UriInfo.class, String.class}); + assertEquals(expected, ori.getMethodToInvoke()); + } @Test public void testFindFromAbstractGenericClass3() throws Exception {
