Environment: OSGi via Equinox with Jersey and MOXy
I have a simple class as ReST component:
package test.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import test.domainobjects.TestDomainObject;
#Path( "/test" )
public class TestTheRest {
#GET
#Produces(MediaType.APPLICATION_JSON)
//#Produces(MediaType.APPLICATION_XML)
public Object getTestEntity() {
return new TestDomainObject();
}
}
and a simple entity
package test.domainobjects;
public class TestDomainObject {
public int fieldA = 1;
public String fieldB = "Some content";
}
When I start my launch configuration and run a GET on <server>:<port>/services/test, I get a 500 error and an exception which I can only see in the debugger:
javax.xml.bind.MarshalException
- with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: Exception [EclipseLink-25007] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor for class test.domainobjects.TestDomainObject was not found in the project. For JAXB, if the JAXBContext was bootstrapped using TypeMappingInfo[] you must call a marshal method that accepts TypeMappingInfo as an input parameter.]
The thing is that I am using the OSGi - JAX-RS Connector (with MOXy provider), so all the wiring happens under the hood.
How am I supposed to supply a descriptor? And why? Shouldn't MOXy be able to convert a POJO to JSON without additional details?
Related
I use Jackson to check and databind input JSON for a REST API, and I would like to log the error when the input doesn’t match a #Valid constraint.
However, the exceptions are throwned as a Response by the API but do not appear in Quarkus’ logs.
How do I log Jackson’s exceptions ?
One has to create a handler for the Jackson exceptions, e.g. using ExceptionMapper.
The following example catches all exceptions of type JsonProcessingException (finer tuning is obviously possible), logs them as SEVERE (using lombok’s #Log annotation) and returns a 400 Bad Request Response including the message. Note that the function has to be toResponse(Exception).
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.java.Log;
#Log
#Provider
public class MyJsonProcessingExceptionHandler implements ExceptionMapper<JsonProcessingException> {
#Override
public Response toResponse(JsonProcessingException exception) {
log.severe(exception.getMessage());
return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Do not forget the #Provider annotation so that the Exception handler acts as a filter on the REST API.
In principle other files of the project (including the controller) do not need to be modified, only this class in its own file.
I use Camel 2.16.0 for a Camel Rest project. I have introduced an abstract type that I need a custom deserializer to handle. This works as expected in my deserialization unit tests where I register my custom deserializer to the Objectmapper for the tests. To my understanding it is possible to register custom modules to the Jackson Objectmapper used by Camel as well (camel json).
My configuration:
...
<camelContext id="formsContext" xmlns="http://camel.apache.org/schema/spring">
...
<dataFormats>
<json id="json" library="Jackson" useList="true" unmarshalTypeName="myPackage.model.CustomDeserialized" moduleClassNames="myPackage.MyModule" />
</dataFormats>
</camelContext>
My module:
package myPackage;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class MyModule extends SimpleModule {
public MyModule() {
super();
addDeserializer(CustomDeserialized.class, new MyDeserializer());
}
}
The Camel rest configuration:
restConfiguration()
.component("servlet")
.bindingMode(RestBindingMode.json)
.dataFormatProperty("prettyPrint", "true")
.contextPath("/")
.port(8080)
.jsonDataFormat("json");
When running the service and invoking a function that utilize the objectmapper I get the exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of myPackage.model.CustomDeserialized, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
Any suggestions on what is wrong with my setup?
I found this solution to the problem and used this implementation for my custom jackson dataformat:
public class JacksonDataFormatExtension extends JacksonDataFormat {
public JacksonDataFormatExtension() {
super(CustomDeserialized.class);
}
protected void doStart() throws Exception {
addModule(new MyModule());
super.doStart();
}
}
I am running a server under WebSphere Application Server (17.0.0.1/wlp-1.0.16.cl170120170227-0220) and have added the changes recommended in this post (How to change Jackson version in JAX-RS app (WebSphere Liberty)) for upgrading the level of Jackson in WAS Liberty. I am using Postman to test my server. When I submit a GET request for an object, it completes successfully. (After adding this change, my server can return my objects in either XML or JSON.). However, I am now seeing these messages in the server console when my server builds the Response object.
[INFO ] FFDC1015I: An FFDC Incident has been created: "org.jboss.weld.exceptions.AmbiguousResolutionException: WELD-001318: Cannot resolve an ambiguous dependency between:
- Managed Bean [class com.ibm.zss.boundary.JaxbJsonProvider] with qualifiers [#Any #Default],
- Managed Bean [class com.ibm.zss.boundary.JsonProvider] with qualifiers [#Any #Default] com.ibm.ws.jaxrs20.cdi.component.JaxRsFactoryImplicitBeanCDICustomizer 425" at ffdc_17.06.13_15.59.57.0.log
com.ibm.zss.boundary.JaxbJsonProvider and com.ibm.zss.boundary.JsonProvider are the classes I added based on the instructions from the previous post.
I also updated my server.xml to include:
<feature>jsonp-1.0</feature>
<feature>jaxrs-2.0</feature>
I've been searching for solutions for handling a WELD ambiguousResolutionException, but most of them address issues with classes where the developer has control over what is being injected. So, I don't know if I have any control over the code that I need to change for this problem.
For completeness, here are the classes which I added to my application:
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
#Provider
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class JaxbJsonProvider extends JacksonJaxbJsonProvider {
}
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
#Provider
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class JsonProvider extends JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(objectMapper.getVisibilityChecker().withFieldVisibility(JsonAutoDetect.Visibility.ANY));
setMapper(objectMapper);
}
}
Can you either mark it an #Specializes or an #Alternative with low #Priority, depending on whether you want it to be used for injection points?
I am adding JSONP support to a REST Service in SPRING4 + JDK 8 + STS 3.6.4
Versions:
Spring 4.1.6.RELEASE
My implementation is based on these links:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-jsonp
The REST service returns ResponseEntity or ResponseBody and use case is to return data in JSONP format.
Added a ControllerAdvice
#ControllerAdvice
public class JsonpCallbackAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpCallbackAdvice(){
super("Callback");
}
}
Here is the Controller of the REST Service
#Controller
public class AcctController {
...
#RequestMapping(value = "/act/{actNum}", method = RequestMethod.GET)
public ResponseEntity<Account> getAccount(#PathVariable("actNum") Integer accountNum) throws Exception {
...
return new ResponseEntity<account>();
}
Here is the relevant web application context configuration
...
<context:component-scan base-package="com.controllers" />
<bean name="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
...
The controller and ControllerAdvice are in same package.
When deployment of the project is initiated following exception is observed
Caused by: java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String
at org.springframework.context.annotation.AnnotationBeanNameGenerator.determineBeanNameFromAnnotation(AnnotationBeanNameGenerator.java:91)
at org.springframework.context.annotation.AnnotationBeanNameGenerator.generateBeanName(AnnotationBeanNameGenerator.java:69)
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:246)
at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84)
at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1427)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1417)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:174)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:144)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:100)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:510)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
This exception was not happening before the ControllerAdvice was added.
Also, it does not happens when #ControllerAdvice annotation is removed
or
the component scan excludes scanning package of the ControllerAdvice class
I tried with Spring version 4.2.0.RC1, and the exception still happens.
Kindly help with resolution of this exception, since not much help is available online.
It seems like a bug in SPRING 4, however am not sure.
I have a simple program using JPA entities to write into a Derby DB (the entities were generated from an existing DB tables). I am using Eclipse and there is a working connection between the Derby client and the server via the EclipseLink Data Source Explorer .
Here is the start of my main():
import javax.persistence.*;
import java.sql.Timestamp;
import java.util.*;
import javax.*;
public class start {
/**
* #param args
*/
private static final String PERSISTENCE_UNIT_NAME = "zodiac";
private static EntityManagerFactory factory;
public static void main(String[] args) {
try {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
System.out.println("after factory gen" );
when I the line with createEntityManager() is executed the following exception is thrown:
[EL Info]: 2012-03-07 22:46:21.892--ServerSession(253038357)--EclipseLink, version: Eclipse Persistence Services - 2.3.2.v20111125-r10461
[EL Severe]: 2012-03-07 22:46:22.064--ServerSession(253038357)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: No suitable driver
Error Code: 0
Any idea what is the problem ? thanks
If you're in Eclipse you need to add the driver to your project classpath. Sounds like you already have a datasource so you must have defined the driver library. All you need to do is "Add Library" to your Java Build Path and choose "Connectivity Driver Definition" and then the Derby driver from the drop down list of available driver definitions.
FYI, there's a checkbox in the New JPA Project wizard where you can select "add driver to classpath" to do this when you create a new project.
Of course you can also add the derbyclient.jar to your classpath directly or define a user library that includes it.
--Shaun