How to work with input parameter in CXF request handler in general?

I did some work with apache CXF (version 2.2.2) JAX-RS. I am trying to enter a data validation level in a CXF request handler before calling a business method. Fortunately :), I ran into the problem of processing input parameters in the request handler (DataValidationHandler). I can read the JSON object manually by following the lines of code in the request handler. But it is duplicated with JSONProvider registered under CXF. Since the input stream of JSON objects can be read only once, otherwise we will encounter the exception "java.io.EOFException: there is no content to map to the object due to the end of input". Moreover, duplicating deserialization of JSON objects will affect performance. The following code is a sample for your reference.

To read the JSON object from the HTTP body manually:

OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class); MultivaluedMap<String, String> values = new MetadataMap<String, String>(); List<Object> objList = JAXRSUtils.processParameters(ori, values, paramMessage); 

Register JSONProvider in CXF JAX-RS:

 <bean id="JSONProvider" class="com.accela.govxml2.jaxrs.util.JSONProvider"></bean> 

Read the JSON object for the Java object from the input stream:

 public Object readFrom(......){ ObjectMapper objectMapper = new ObjectMapper(); Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType)); Return result; } 

I am dealing with a path parameter manually following the lines of code.

 OperationResourceInfo ori = paramMessage.getExchange().get(OperationResourceInfo.class); URITemplate t1 = ori.getClassResourceInfo().getURITemplate(); URITemplate t2 = ori.getURITemplate(); UriInfo uriInfo = new UriInfoImpl(paramMessage, null); MultivaluedMap<String, String> map = new MetadataMap<String, String>(); t1.match(uriInfo.getPath(), map); String str = map.get(URITemplate.FINAL_MATCH_GROUP).get(0); t2.match(str, map); String pathParameter= null; if (map.containsKey("pathParam") && !ValidationUtil.isEmpty(map.get("pathParam"))) { pathParameter= map.get("pathParam").get(0); } 

My questions are here:

  • How to work with the POST / PUT input parameter of the http object in the request handler in general?
  • How to avoid performance issues to efficiently read input parameters?
  • Is there a way to implement the verification level (handler / interceptor) between the CXF parameter readings (JSONProvider) and the business method call?
  • Is there an elegant way to handle the path parameter?

Thanks for your help. Any comments and suggestions would be appreciated.

Regards, Dylan

+4
source share
2 answers

I found another way to introduce the DataValidation Interceptor into the parameter reading phase. We can reuse the deserialized input model from the contents of the message, which is deserialized by the JSONProvider registered in the framework. It can improve performance by deserializing the input model only once.

 public class DataValidationInInterceptor extends AbstractPhaseInterceptor<Message> { public DataValidationInInterceptor() { super(Phase.READ); } @Override public void handleMessage(Message message) { OperationResourceInfo ori = message.getExchange().get(OperationResourceInfo.class); Method method = ori.getMethodToInvoke(); Class<?>[] types = method.getParameterTypes(); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (int i = 0; i < types.length; i++) { Class<?> type = types[i]; List obj = (List) message.getContent(List.class); System.out.println(obj); System.out.println(type); } } } 
+1
source

After research, I can read the input stream twice in accordance with the following answer to the question ( Read the stream twice ).

However, the performance of deserializing a JSON object is still a concern. Who has the best solution for this?

Intercept the request and change the contents of the message from CoyoteInputStream to ByteArrayInputStream, so I can read InputStream twice.

 InputStream in = message.getContent(InputStream.class); if (in != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(in, baos); byte[] bytes = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); message.setContent(InputStream.class, bais); } 

Reset ByteArrayInputStream before reading the JSON object for the Java object from the input stream:

 public Object readFrom(......){ ObjectMapper objectMapper = new ObjectMapper(); if (entityStream.markSupported()) { entityStream.reset(); } Object result = objectMapper.readValue(entityStream, TypeFactory.defaultInstance().constructType(genericType)); return result; } 
0
source

Source: https://habr.com/ru/post/1414491/


All Articles