Restlet Client doesnt communicate well with Jersey Service - rest

I want to realise a restlet client for my jersey service. I know that the service works, because I already developed a jersey client for it. But it seems like jersey and rest get problems to communicate with each other.
Jersey Service
Ressource:
#Path("/object")
#RolesAllowed({"admin", "user"})
public class ObjectResourceBean implements ObjectResourceIF {
#POST
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response postObject(JAXBElement<ObjectDTO> object) {
ObjectDTO c = object.getValue();
String generatedId = generateID();
c.setObjectId(generatedId);
c.setOwner(sec.getUserPrincipal().getName());
return postAndGetResponse(c);
}
private Response postAndGetResponse(ObjectDTO object) {
Response res;
res = Response.created(UriBuilder.fromUri(uriInfo.getAbsolutePath() + "/" + object.getObjectId()).build()).entity(object).build();
ObjectDAO.instance.getObjectDao().put(object.getObjectId(), object);
System.out.println("Response: " + res);
}
return res;
}
Restlet Wrap Interface:
#Path("/object")
#RolesAllowed({"admin", "user"})
public interface ObjectResourceIF {
#Post
public Response postObject(JAXBElement<ObjectDTO> object);
}
Already here I can't work with Jersey Annotations like #POST. I have to use #Post from Restlet Framework. But thats not the real problem.
Restlet Client
ClientResource service = new ClientResource("http://localhost:8080/com-project-core/rest");
service.setChallengeResponse(ChallengeScheme.HTTP_BASIC, "admin", "xxx");
service.getReference().addSegment("object");
// *create object*
JAXBElement<ObjectDTO> object = new JAXBElement<ObjectDTO>(new QName("object"), ObjectDTO.class, objectOne);
ObjectResourceIF objectResource = service.wrap(ObjectResourceIF.class);
List<Preference<MediaType>> acceptedMediaTypes = new ArrayList<Preference<MediaType>>();
acceptedMediaTypes.add(new Preference(MediaType.APPLICATION_JSON));
service.getClientInfo().setAcceptedMediaTypes(acceptedMediaTypes);
Response res = objectResource.postObject(object);
I just get a Internal Server Error (500).
Internal Server Error (500) - The server encountered an unexpected condition which prevented it from fulfilling the request
at org.restlet.resource.UniformResource.toObject(UniformResource.java:649)
at org.restlet.resource.ClientResource$1.invoke(ClientResource.java:1669)
at $Proxy12.postObject(Unknown Source)
at com.project.restlet.RestletConnectedTest.postObject(RestletConnectedTest.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: objectId : objectId
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:71)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:86)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:96)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:52)
at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:136)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:33)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:923)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:909)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:861)
at org.restlet.ext.xstream.XstreamRepresentation.getObject(XstreamRepresentation.java:166)
at org.restlet.ext.xstream.XstreamConverter.toObject(XstreamConverter.java:200)
at org.restlet.service.ConverterService.toObject(ConverterService.java:161)
at org.restlet.resource.UniformResource.toObject(UniformResource.java:647)
... 27 more
On Server Side the request gets done to
return res;
When I try it without wrapping the Interface with
service.post(object, MediaType.APPLICATION_JSON).write(System.out);
it works!
As I said, the Jersey Client works as well.
Maybe the transfered Class ObjectDTO is useful for the solution:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ObjectDTO implements Serializable{
/**
*
*/
private static final long serialVersionUID = -8545841080597549468L;
#XmlElement(name="objectId")
private String objectId;
#XmlElement(name="owner")
private String owner;
#XmlElement(name="objectName")
private String objectName;
public ObjectDTO() {
}
public ObjectDTO(String objectName) {
this.objectName = objectName;
}
public String getObjectId() {
return objectId;
}
public void setObjectId(String objectId) {
this.objectId = objectId;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
}
I tried it without serializable as well. Also without #XmlElement and #XmlAccessorType(XmlAccessType.FIELD). As well I tried it with
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
annotation at the interface.

We had the same Problem with a Jersey server and Restlet client, but with a get Request.
With a Restlet client to Restlet server communication we hat no problems. So the only difference we could see was, that Restlet server implementation wraps the full qualified class name of the marshalled POJO as a JSON Object around the JSON Object which contains the POJOs payload.
package com.xyz;
public class ExamplePojo implements Serializable{
private static final long serialVersionUID = 1L;
private String var;
public ExamplePojo(){
}
//...
}
Resulting json string on Restlet server:
{"com.xyz.ExamplePojo":{"var":"10:23:53 30.10.2012"}}
but Jersey server in its default implementation if producing MediaType.APPLICATION_JSON doesn't. Resulting json string on Jersey server:
{"var":"10:23:53 30.10.2012"}
The problem was, that if we attempt communication with the Jersey server via a Restlet client, we got the same error like in your stacktrace with the root cause:
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: var : var
The soulution in our case was, that we explicitly had to define the JacksonConverter if using a Restlet client with a Jersey server implementation.
So we put the libraries from the Restlet zip on our build path of the client project
org.restlet.ext.jackson.jar
org.codehaus.jackson.core.jar
org.codehaus.jackson.mapper.jar
(interface of the resource)
public interface PojoResource {
#Get("json")
public ExamplePojo retrieve();
}
and then we add explicit the JacksonConverter to the registered converters
public ExamplePojo doRequest(){
ClientResource cr = new ClientResource( url );
// this is essential for Restlet-Jersey marshalling
Engine.getInstance().getRegisteredConverters().add( 0, new JacksonConverter() );
PojoResource resource = cr.wrap( PojoResource.class );
return resource.retrieve();
}
and everything worked fine.
Note that an explicit call to
Engine.getInstance().getRegisteredConverters().add( 0, new JacksonConverter() );
on a Reslet-Client to Restlet-Server communication did not work, but led to an
org.codehaus.jackson.map.JsonMappingException
because of the wrapping JSON Object 'com.xyz.ExamplePojo' as an unrecognized field, which must be marked as ignoreable.
So in your case it seems that Restlet doesn't find a converter for the unmarshalling either, so try to specify an explicit one.

Related

Jax-RS Content-Type priority

I've got a JavaEE application with a simple REST service where I want to support the content types application/json and application/xml. Everything works as expected when the client sends an Accept header with one of these content types in it.
When this header is missing though, I want to answer with application/json as default, but no matter what I've tried so far, application/xml will be used.
Configuration Class
#ApplicationPath("api")
public class ApplicationConfig extends Application {
}
Service Class
#Path("users")
public class UserResource {
#Path("/{username}")
#GET
// The following variants didn't change the behaviour:
// #Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
// #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + ";q=0.5"})
// #Produces({MediaType.APPLICATION_JSON + ";q=1.0", MediaType.APPLICATION_XML + ";q=0.5"})
// #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + ";qs=0.5"})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public User userDetails(#PathParam("username") final String username) {
return new User();
}
}
(Generated) User Class
The class I'm returning is generated (maven-jaxb2-plugin) with JAXB annotations to support XML without further configuration:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "User", propOrder = {
"username"
})
#XmlRootElement(name = "user")
public class User
implements Serializable, Equals, HashCode
{
private final static long serialVersionUID = 1701L;
#XmlElement(required = true)
protected String username;
// ...
}
Further Information
JavaEE 7
Java 8
Same behaviour with Glassfish 4.1 and Wildfly 9.0.1

Jersey JAX-RS Glassfish 4 throwing java.lang.IllegalStateException

I am creating a simple RESTful service
#Path("/book")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Stateless
public class RestBookService {
#PersistenceContext(unitName="bookPU")
private EntityManager em;
#Context
protected UriInfo uriInfo;
#POST
public Response createBook(Book book) {
if (book == null)
throw new BadRequestException();
em.persist(book);
URI bookUri = uriInfo.getAbsolutePathBuilder().path(book.getId() + "").build();
return Response.created(bookUri).build();
}
}
The Book is simple JPA entity
#Entity
#XmlRootElement
public class Book {
static Logger log = Logger.getLogger(Book.class.getName());
public static final String FIND_ALL = "Book.find_all";
#Id
#GeneratedValue
private int id;
#Column(nullable=false)
private String title;
#Column
private Float price;
}
//Just giving a relevant code. There are getters/setters and the constructor
I am deploying the service using Maven on Glassfish 4.1
I am using
Jersey Container 2.13
Hibernate 4.3.5 Final
Mysql 5.1
and when I try to create a book using cURL as follows
curl -X POST --data-binary "<book><price>12.5</price><title>Book Title</title></book>" -H "Content-Type: application/xml" http://localhost:8080/book-service/rs/book -v
It is throwing following exception.
StandardWrapperValve[jersey-serlvet]: Servlet.service() for servlet jersey-serlvet threw exception
java.lang.IllegalStateException: Not inside a request scope.
at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149)
at org.glassfish.jersey.process.internal.RequestScope.current(RequestScope.java:228)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:156)
at org.jvnet.hk2.internal.MethodInterceptorImpl.invoke(MethodInterceptorImpl.java:74)
at org.jvnet.hk2.internal.MethodInterceptorInvocationHandler.invoke(MethodInterceptorInvocationHandler.java:62)
at com.sun.proxy.$Proxy239.getAbsolutePathBuilder(Unknown Source)
at com.services.bookrestservice.rest.RestBookService.createBook(RestBookService.java:44)
[There is another question similar to this but I have done exactly the same which is given in the answer still I am getting the exception. Also, I have gone through https://java.net/jira/browse/JERSEY-2241 but it seems to be in resolved state with the resolution as cannot reproduce. ]
Can somebody please help me.
EDIT1
I have changed from Stateless annotation to RequestScoped annotation as suggested by #HankCa. It is throwing following exception now.
'javax.persistence.TransactionRequiredException
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:161)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:151)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:281)
at com.services.bookrestservice.rest.RestBookService.createBook(RestBookService.java:44)
'
Not sure why this exception because it is already in persistentcontext.
EDIT2
#HankCa suggested I did the following change.
Removed
#Context
protected UriInfo uriInfo;
And updated the method signature as
#POST
public Response createBook(Book book, #Context UriInfo uriInfo) {
And the service is working as expected. Thanks HankCa for your help.
Yes I stared at this one for far too long and my solution was as you found at Why is my Jersey JAX-RS server throwing a IllegalStateException about not being in RequestScope?. This was a year ago and I haven't hit it again (though I have been out of EJB land for a while) so I'll give it my best shot.
Specifically I would make these mods:
Add #RequestScoped
Put the #Context UriInfo uriInfo in the method or class. In the end i seemed to have gone in the method like:
This is code (and this is a line to separate the list from the code so the code shows as code!)
#Path("/user")
#Produces({ MediaType.APPLICATION_JSON })
#Consumes({ MediaType.APPLICATION_JSON })
#RequestScoped
public class UserResource {
...
#PermitAll
#POST
public Response signupUser(CreateUserRequest request, #Context UriInfo uriInfo) {
AuthenticatedUserToken token = userService.createUser(request, Role.authenticated);
verificationTokenService.sendEmailRegistrationToken(token.getUserId());
URI location = uriInfo.getAbsolutePathBuilder().path(token.getUserId()).build();
return Response.created(location).entity(token).build();
}
I hope that helps!
Cheers,
bbos

CORBA exception in EJB application

I've got a problem with EJB/Glassfish. I'm working on a client-server application in which the client creates an entity object and must send it to the server application, which must persist the entity in its database. I've choose to use session beans to communicate with the server.
I've implemented some simple cases in which a method in the session bean takes as input a string or an int and it works fine. The problem arises when I try to give an entity object as input.
I report my entity class:
#Entity
public class Example implements Serializable {
private static final long serialVersionUID = 1L;
#Id
String nome;
public void setNome(String nome) {
this.nome = nome;
}
public String getNome() {
return nome;
}
Here my session bean:
#Stateless
public class GestoreLibreriaRemoto implements GestoreLibreriaRemotoRemote {
#Override
public String getProva(Example prova) {
return prova.getNome();
}
Here my client application:
public class GestoreLibreriaLocale {
public static void assegnaCategoriaACopia(CopiaUtente copia, Categoria categoria) throws
public void prova() {
GestoreLibreriaRemotoRemote gestore = lookupGestoreLibreriaRemotoRemote();
Example example = new Example();
prova.setNome("hodor");
System.out.println(gestore.getProva(example));
}
private GestoreLibreriaRemotoRemote lookupGestoreLibreriaRemotoRemote() {
try {
Context c = new InitialContext();
return (GestoreLibreriaRemotoRemote) c.lookup("java:global/ServerMDB/ServerMDB-ejb/GestoreLibreriaRemoto");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}
In my main class I simply call GestoreLibreriaLocale.prova() and i get the following error:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.glassfish.appclient.client.acc.AppClientContainer.launch(AppClientContainer.java:446)
at org.glassfish.appclient.client.AppClientFacade.main(AppClientFacade.java:166)
Caused by: javax.ejb.EJBException: java.rmi.MarshalException: CORBA MARSHAL 1330446346 Maybe; nested exception is:
org.omg.CORBA.MARSHAL: ----------BEGIN server-side stack trace----------
org.omg.CORBA.MARSHAL: AVVERTENZA: 00810010: Error from readValue on ValueHandler in CDRInputStream vmcid: OMG minor code: 10 completed: Maybe
at com.sun.proxy.$Proxy139.valuehandlerReadError(Unknown Source)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.readRMIIIOPValueType(CDRInputStream_1_0.java:912)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.read_value(CDRInputStream_1_0.java:1005)
at com.sun.corba.ee.impl.encoding.CDRInputObject.read_value(CDRInputObject.java:518)
at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl$14.read(DynamicMethodMarshallerImpl.java:383)
at com.sun.corba.ee.impl.presentation.rmi.DynamicMethodMarshallerImpl.readArguments(DynamicMethodMarshallerImpl.java:450)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:171)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatchToServant(ServerRequestDispatcherImpl.java:528)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatch(ServerRequestDispatcherImpl.java:199)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequestRequest(MessageMediatorImpl.java:1549)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:1425)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleInput(MessageMediatorImpl.java:930)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:213)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:694)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.dispatch(MessageMediatorImpl.java:496)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.doWork(MessageMediatorImpl.java:2222)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.sun.corba.ee.impl.io.IIOPInputStream
at com.sun.corba.ee.impl.io.ValueHandlerImpl.createInputStream(ValueHandlerImpl.java:820)
at com.sun.corba.ee.impl.io.ValueHandlerImpl.readValue(ValueHandlerImpl.java:263)
at com.sun.corba.ee.impl.encoding.CDRInputStream_1_0.readRMIIIOPValueType(CDRInputStream_1_0.java:903)
... 16 more
The error log continues, I don't report the whole log but if you need it I can post it.
Please help me, I'm working on it from days without resolving it.
Thanks for the attention,
Francesco
This seems to be a bug in the current Java versions (e.g. 1.7.0_55 and 1.8.0_05), have a look at this issue: GLASSFISH-21047
To make it work, install either an older or a newer Java version (e.g. 1.7.0_051 or 1.8.0_020).
See also:
Exception inside CORBA when accessing a remote bean

Marshalling List<String> with JAX-RS

I'm used to working with jax-ws where a wsdl file is generated, and a client can then be generated based on this wsdl file and its xsd(s) using a maven plugin. Using this client is no hassle at at, and you don't have to really think about what happens in the background, like marshalling, http transfer and such.
I'm currently working on a jax-rs project using jaxb to unmarshal objects. One of the methods there returns a list of strings, but it seems that jaxb does not know how to marshal this, which is kinda surprising as it does know how to marshal a list of entities (ex, customers).
Also, I have written a client for the jax-rs service on my own, handling both http responses and unmarshalling of the payload using jaxb. Marshalling and unmarshalling with jaxb is a real hassle since it cannot automatically marshall or unmarshall list of entities that is added to its context, even less lists of strings.
I would like to know if there is some neat way to get all of this for free using restful webservices? This would have to be quite lightweight, and the clients must be easy to distribute.
Thanks!
Runar
The service method that is not working using jaxrs and jaxb:
#GET
#Path("/{customerId}")
#Produces(MediaType.APPLICATION_XML)
public List<String> isCustomerLocked(#PathParam("customerId") Long customerId) {
}
Client code that attempts to marshall/unmarshall text payload. Classes added to the jaxbcontext not shown:
javax.xml.bind.Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(obj, stringwriter)
javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.unmarshal(inputstream)
I'd use JAXB to wrap the data. For a simple List<String> this may look as overkill. But in most cases you want to un-/marshall Resource Representations, not simple objects.
Remember: REST ist not RPC!
If you really want tom un-/marshall List<String> write a JAX-RS Provider. But I'd prefer using JAXB.
S.java
#XmlRootElement
public class S {
private String s;
public S() {
}
public S(String s) {
this.s = s;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
}
Ss.java
#XmlRootElement(name="ss-wrapper")
public class Ss {
private List<S> ss;
public List<S> getSs() {
return ss;
}
public void setSs(List<S> ss) {
this.ss = ss;
}
public Ss(List<S> ss) {
this.ss = ss;
}
public Ss() {
}
}
JAX-RS class
#Path("/strings")
#GET
#Produces(MediaType.APPLICATION_XML)
public Response getListOfStrings() {
S s1 = new S("foo");
S s2 = new S("bar");
List<S> strings = new ArrayList<S>();
strings.add(s1);
strings.add(s2);
Ss ss = new Ss(strings);
return Response.ok(ss).build();
}
XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ss-wrapper>
<ss>
<s>foo</s>
</ss>
<ss>
<s>bar</s>
</ss>
</ss-wrapper>

Morphia-MongoDB - "Please override this method for user marked Id field entity"

I am following a tutorial mention on code.google, but my example fails giving the following trace :
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.google.code.morphia.mapping.MappedClass.callLifecycleMethods(MappedClass.java:323)
at com.google.code.morphia.mapping.Mapper.toDBObject(Mapper.java:371)
at com.google.code.morphia.DatastoreImpl.entityToDBObj(DatastoreImpl.java:674)
at com.google.code.morphia.DatastoreImpl.save(DatastoreImpl.java:722)
at com.google.code.morphia.DatastoreImpl.save(DatastoreImpl.java:802)
at com.google.code.morphia.DatastoreImpl.save(DatastoreImpl.java:796)
at models.com.vlist.activity.classes.TestMongoData.testUserData(TestMongoData.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.code.morphia.mapping.MappedClass.callLifecycleMethods(MappedClass.java:304)
... 28 more
Caused by: java.lang.UnsupportedOperationException: Please override this method for user marked Id field entity: models.com.vlist.activity.classes.User
at play.modules.morphia.Model.setId_(Model.java:284)
at play.modules.morphia.Model.generateId_(Model.java:299)
... 33 more
My example is as following:
import javax.persistence.Entity;
import org.bson.types.ObjectId;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.google.code.morphia.annotations.Id;
import play.modules.morphia.Model;
#Entity
public class User extends Model {
#Id ObjectId id;
private String firstName;
private String lastName;
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName(){
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
}
and
import static org.junit.Assert.*;
import org.junit.Test;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
public class TestMongoData {
#Test
public void testUserData() {
User user = new User();
user.setFirstName("first");
user.setLastName("last");
Morphia morphia = new Morphia();
Datastore ds = morphia.createDatastore("testData");
ds.save(user);
}
}
What could be wrong?
Update:
When I use play test, i see the following:
08:01:55,783 ERROR ~
#66h1bm10d
Internal Server Error (500) for request GET /#tests
Compilation error (In {module:morphia}/app/morphia/Filter.java around line 8)
The file {module:morphia}/app/morphia/Filter.java could not be compiled. Error raised is : The type Filter is already defined
play.exceptions.CompilationException: The type Filter is already defined
at play.classloading.ApplicationCompiler$2.acceptResult(ApplicationCompiler.java:246)
at org.eclipse.jdt.internal.compiler.Compiler.handleInternalException(Compiler.java:672)
at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:516)
at play.classloading.ApplicationCompiler.compile(ApplicationCompiler.java:278)
at play.classloading.ApplicationClassloader.getAllClasses(ApplicationClassloader.java:406)
at play.Play.start(Play.java:453)
at play.Play.detectChanges(Play.java:574)
at play.Invoker$Invocation.init(Invoker.java:186)
at Invocation.HTTP Request(Play!)
The problem comes from your #Entity definition. You're using JPA annotation while you should use the Morphia ones.
On startup, the Morphia plugin will retrieve all classes marked with the morphia Entity annotation and enhance them with various injected model methods. You're receiving this exception because your model class hasn't been enhanced.
If you annotate #Id then play morphia won't enhance your model by providing right implementation for void setId_(Object id) method. Try defining one yourself like this.
#Entity
class User extends Model {
#Id String email;
protected void setId_(Object id) {
}
}
Try removing the #Id ObjectId id; from your model. The Morphia Module for Play Framework will add the id for you.
Then make the fields public and remove the getter/setter methods.
public String firstName;
public String lastName;
Also, your Entity import is incorrect. Try this
import com.google.code.morphia.annotations.Entity;
Try this for a test case:
import static org.junit.Assert.*;
import org.junit.Test;
import play.test.UnitTest;
public class TestMongoData extends UnitTest {
#Test
public void testUserData() {
User user = new User();
user.setFirstName("first");
user.setLastName("last");
user.save();
}
}
It's seems that you have defined the morphia module in the dependency file and in the application conf file.
In the dependencies file : - play -> morphia [1.2.1beta6,)
In the application conf file : module.morphia=${play.path}/modules/morphia
You must removed one of this declaration otherwise the morphia module is loaded twice ...