Returning JSON from a RESTful service using CXF DOSGI - cxf

I have a simple service which is annotated with JAX-RS annotations and includes the #Produces("application/json") annotation. I have set up the following properties when I register the service (I am using DS but that shouldn't matter):
service.exported.interfaces -> *
service.exported.configs -> org.apache.cxf.rs
org.apache.cxf.rs.address -> myURI
When I run my application I can hit the URL, but my browser returns:
No message body writer has been found for response class MyClass.
My OSGi console displays:
Jan 11, 2012 2:29:48 PM org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor writeResponseErrorMessage
WARNING: No message body writer has been found for response class MyClass.
I read the documentation and thought maybe I needed to register a JSON provider. In may Activator I added:
bundleContext.registerService(new String[] { "javax.ws.rs.ext.MessageBodyReader",
"javax.ws.rs.ext.MessageBodyWriter" },
new org.apache.cxf.jaxrs.provider.JSONProvider(), null);
but this has not made any difference.
How do I fix the "No message body writer has been found for response class MyClass." error message?

No message body writer means that your json provider does not understand how to marshal your class that you returned into JSON. If you are using the default JSONProvider, then you are using Jackson, which uses JAXB annotations. In other words, the class that you return should have a #XmlRootElement annotation on the class level.

Related

CVE-2021-20289 - migrate from Resteasy jaxrs 3 to RESTEasy > 4.6.0

The vulnerability scan system detects a CVE regarding RestEasy 3.7.0: CVE-2021-20289
https://nvd.nist.gov/vuln/detail/CVE-2021-20289, which states RESTEasy should upgrade to above 4.6.0.Final. But, here comes the question: RESTEasy > 4 does not contains this submodule.
I noticed that in https://developer.jboss.org/en/resteasy/blog/2019/03/28/resteasy-4-is-coming-soon, it is stated that
the big resteasy-jaxrs and resteasy-client modules have been split into resteasy-core-spi, resteasy-client-api, resteasy-core and resteasy-client, with the first and second ones to be considered as public modules, for which we're expected to retain backward compatibility till next major release.
If I comment out the resteasy-jaxrs dependency from pom.xml, I will get error of cannot access class org/jboss/resteasy/microprofile/config/ResteasyConfigFactory. But I cannot find it in resteasy-core-spi or rest-client-api module. The nearest is resteasy-4.7.4.Final/resteasy-core-spi/src/main/java/org/jboss/resteasy/spi/config/ConfigurationFactory.java. But if the class name changed, there would not be easy migration. Or am I missing something?
Actually according to https://issues.redhat.com/browse/RESTEASY-2878, this CVE is fixed in 3.15.2. So I am lost.
At last I
migrate from resteasy 3 to 4, abandon resteasy-jaxrs and introduce resteasy-client-api and resteasy-client
switch from org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder to org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl, even though it's under internal package, it's a public class and Javadoc does not suggest against using it directly. And this implementation is quite standard, and introduces the minimal fraction while migrating. I also compared the default values set in the class, such as connectionPoolSize and so on, they are the same as in resteasy-jaxrs 3.
The code change is minimal:
// before
private ResteasyClient client = new ResteasyClientBuilder()
.connectionPoolSize(CONNECTION_POOL_SIZE)
.build();
// after
private ResteasyClient client = new ResteasyClientBuilderImpl()
.connectionPoolSize(CONNECTION_POOL_SIZE)
.build();
And the provider:
I am receiving content type text/plain. In Resteasy-jaxrs 3, I used ResteasyJackson2Provider and it implements MessageBodyReader and MessageBodyWriter, and it worked. Now, in Restyeasy 4, the content type check seems to be stricter and isReadable() of this same named class only accepts Content-Type of null or contains json. As I receive text/plain, it no longer works.
For reading plain text, I suggest using StringTextStar. A new class in Resteasy 4.7.5, and it seems to work. Reading inputstream and write as string, just what I need. Check its impl.
ResteasyClient client1 = new ResteasyClient()
.register(new ResteasyJackson2Provider()) // for JSON
.build();
ResteasyClient client2 = new ResteasyClient()
.register(new StringTextStar()) // for text/plain
.build();
And the auto-closeable client:
Now you need to use try-finally or try-with-resources to close it. It will be closed automatically if you don't, but you receive a warning: Closing an instance of ApacheHttpClient43Engine for you and so.

#AfterReturning from ExceptionHandler not working

I have a GlobalExceptionHandler class which contain multiple methods annotated with #ExceptionHandler.
#ExceptionHandler({ AccessDeniedException.class })
public final ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
I have a AOP which is suppose to be triggered after the exception handler returns response.
#AfterReturning(value="#annotation(exceptionHandler)",returning="response")
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
But the #AfterReturning is not triggered after the handler returns a valid response.
Tried full qualified name but not working
#AfterReturning(value = "#annotation(org.springframework.web.bind.annotation.ExceptionHandler)", returning = "response"){
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
Please go through the documentation to understand the proxying mechanisms in Spring framework.
Assuming the ExceptionHandler code written was of the following format
#ControllerAdvice
public class TestControllerAdvice {
#ExceptionHandler({ AccessDeniedException.class })
final public ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
}
key points from the documentation pertaining to the question are
Spring AOP uses either JDK dynamic proxies or CGLIB to create the
proxy for a given target object.
If the target object to be proxied implements at least one
interface, a JDK dynamic proxy is used. All of the interfaces
implemented by the target type are proxied. If the target object
does not implement any interfaces, a CGLIB proxy is created.
With CGLIB, final methods cannot be advised, as they cannot be overridden in runtime-generated subclasses.
OP identified the issue based on the comments and hints , this answer is for any future references.

Spring RestTemplate and JSON how to ignore empty Arrays deserialization?

I am currently using Spring 4.1.6 with a RestTemplate to consume a third party webservice with JSON which I cannot change its behavior.I am using Jackson databind v2.6.0.
Problem: Sometimes the service returns for a member a hashmap {member:{"key":"value",...}} sometimes the same member is just an empty array {member:[]}. So I can not ignore the property by default.
Is there a way to configure the deserialization to ignore empty arrays? I saw a jackson property "WRITE_EMPTY_JSON_ARRAYS" but I am not quite sure how I can use it with my restTemplate and spring configuration.
Are there other possiblities e.g. use some combination of #JsonXXX Annotations? I saw #JsonSerialize which can be used on class level, but I don't like to write a deserializer for all my classes just to handle this situation (However if there is no other way of course I will do)
Example responses to llustrate the behavior of the service:
response with a hashmap
{"id":170,"categories":{"13":"caro"}}
response with empty array of the same member
{"id":170,"categories":[]}
Example of my RestTemplate usage:
BasicAuthRequestFactory requestFactory = new BasicAuthRequestFactory(httpClient);
restTemplate = new RestTemplate(requestFactory);
Article a = restTemplate.getForObject(new URI("http://..."), Article.class);
Error:
caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
at [Source: java.io.PushbackInputStream#4aa21f9d; line: 1, column: 1456] (through reference chain: ResponseArticleWrapper["data"]->Article["categories"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
Example of my current annotated class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(Include.NON_NULL)
public class Article {
#JsonProperty("id")
private Integer id;
#JsonProperty("categories")
private Map<Integer,String> categories = new HashMap<Integer,String>();
}
Thank you in advance for any hints and examples.
Since jackson-databind 2.5 there is DeserializationFeature for handling this case. It's turned off by default, so you need to configure it in your ObjectMapper:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
return objectMapper;
}
You can see how the custom ObjectMapper for RestTemplate is configured here: How can we configure the internal Jackson mapper when using RestTemplate?
After you're done with the configuration, you can just let Spring wire it for you in your class:
#Autowired
private RestOperations restTemplate;
and use the provided restTemplate instance.

Not able to serialize List<Object> to json using resteasy jackson provider and jaxb annotations

I have added resteasy-jackson provider jar in my pom.xml
I have one pojo class annotated with jaxb annotations :
Request.java
#XmlElement
public List<Object> getListSO() {
return listSO;
}
I have written an resteasy client to access a rest webservice. I am passing this request object as a parameter to webservice.
Rest Webservice
#POST
#Path("/authorizefields")
#Produces("application/json; charset=ISO-8859-1")
#Consumes("application/json; charset=ISO-8859-1")
public Reply getFields(Request request) {
}
Now from rest client if i add some object to list say
listSO.add(new Sample());
request.setListSO(listSO);
and pass it to the rest webservice I am not able to get sample object in ws.
Is there any jaxb or jackson annotation needed to put on list of object to support polymorphism?

Using Objectify For retrieving from Datastore- Error :Did you forget to inherit required module

I am using Objectify for retrieving data From datastore in GWT,But i get the Following Error :
[ERROR] No source code is available for type
com.logins.entity.experts; did you forget to inherit a required
module?
I have Client->entity->Server and i did define the RPC properly with RemoteServicePath.
i intiaized the Rpc in client side
final findexpertAsync
finexp=(findexpertAsync)GWT.create(findexpert.class);
GWT compiler throws Error at the method i call,
finexp.expert(expnam, new AsyncCallback<ArrayList<experts>>()
Note:
1) findexpert and FindexpertAsync are the RPC interface which has a method for retriving data from datastore
2)com.logins.entity.experts:experts is a server class.
Any guesses where i am going wrong ?
All classes directly or indirectly referenced from the client must be part of the client source path. You can't access server-only code from GWT. In this case, class "experts" needs to be part of the GWT-compiled client code.
Also: You should capitalize Java class names.

Resources