How can I tell Jersey to use my MessageBodyReader instead using JAXB? - jaxb

Basically, I have some models which all use JAXB. However, I have some highly custom functionality to convert to JSON and back so I want to write my own MessageBodyReader/Writer to do the job for me.
Right now, the writing portion is done: if i return one of my models from a REST resource, it goes through my writer. But when I try and accept a model as a FormParam, it doesnt use my MessageBodyReader and instead attempts to unmarshal it using JAXB (which fails).
So how I can tell Jersey to use my Reader instead?
public TestModel testProvider(#FormParam("model") TestModel input){ //doesnt work
return new TestModel(); //this part works!
}

Mark as #Provider
Add the configuration to your web.xml EX:
<init-param><param-name>com.sun.jersey.config.property.packages</param-name> <param-value> your.package.that.contains.the.provider </param-value> </init-param>

Since your writer works, but your reader does not, I'm guessing you have just missed something in your configuration. Some things to check:
Do you have the #Provider annotation on your reader?
Did you correctly implement the isReadable method on your reader?
Do you have the appropriate #Consumes annotation on the reader, does its media type match the media type specified on your service method?

Related

Why i can't put more than 1 setters of same argument type in class which implements genericHandler in dsl?

I have created a class implementing GenericHandler to use in .handle() method. I have setters for the class, but if i have more than 1 setter with same argument type, i am getting "Found Ambiguous parameter type".
Why there is such restriction?
That's just because ServiceActivatingHandler is based on the MessagingMethodInvokerHelper logic on background to determine the appropriate messaging method. And setters are candidate for that purpose.
So, if you really hae several of them with the same param type, we end up with ambiguity issue.
To fix your case, I suggest mark your Object handle(P payload, Map<String, Object> headers); implementation with #ServiceActivator.
From other side I agree that it is not so good as we expect from Framework. So, feel free to raise a JIRA issue on the matter and we will fix .handle() to be more strict and rely only on the handle() method from the GenericHandler implementation.
I faced the same problem while using Spring integration while using a service adaptor. Could not define multiple properties of type java.lang.String - I would get a IllegalArgumentException claiming "ambiguous parameters".
After finding no solution to the issue, decided to just create a class to encapsulate those properties, configure this as a bean, and then inject it into the spring-integration config.

Jersey 2 - JAXB

Using Jersey 2 m13-3 in Tomcat 7, I'm trying to post XML and have JAXB automatically unmarshal it.
My method signature is something like:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces( {"text/xml"})
public Response setFoo(
myXJC.generatedclass.Foo foo
)
I get a 400 bad request, but no exception (that I can find).
Testing with:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces( {"text/xml"})
public Response setFoo() { ... }
I'm confident this method is being invoked in response to a request.
But as soon as I add arg myXJC.generatedclass.Foo, it isn't.
Do I need something special in my class which extends javax.ws.rs.core.Application to use JAXB? Something ResourceConfig related perhaps? Any extra jersey specific jars?
I see there is a jersey-media-moxy. I'd be happy to get it working with MOXy, but ideally it would also work with Sun/Oracle JAXB.
I've had a look at the source code of:
<dependency>
<groupId>org.glassfish.jersey.examples</groupId>
<artifactId>jaxb</artifactId>
<version>2.0-m13-3</version>
</dependency>
but I'm still having trouble.
Turns out that when I generated the classes from my XSD using XJC, I'd left an incorrect target namespace in there.
The XML I was posting was not namespace qualified, but the generated classes were expecting a namespace.
Once I fixed this, things worked fine.

Use JAXB to marshall bean in the service layer

I use Jersey with JAXB to convert my response to XML. I have several methods that consume XML from the Request Body. I can specify the bean as a parameter to the method being called and JAXB will be used to automatically transform the request body data to that bean, or fail if it's not compatible.
This works great for the majority of all my cases, and I have not had the need to write a MessageBodyReader or MessageBodyWriter to handle the transformation to and from. I have this one instance where I need the request body to be mapped to the bean, but I also need the original XML that was in the body of the request. I need to store that in the DB.
I've tried getting to the request body through the HttpContext, and can't figure out how - I just see the header values and URI values. I tried through the HTTPServletContext as well ending in the same result.
Is there a way to capture the request body as it is before it's transformed or after? Will I need to create a MessageBodyReader to handle this case? It seemed like those were used to map the contents to a bean, which I already have functioning, so I didn't think that was the solution. But, perhaps in the MessageBodyReader I can put the request body into some variable and pass it along while still transforming the data to the beans. That still seems kind of more work than is needed. I would think I could get to the body through the request somehow.
Update:
I tried getting the body from ContainerRequest object using the getEntity method.
String xmlString = request.getEntity(String.class);
And, that worked great. The request body is captured in that property and I can add it to the request properties to access later in the resource, etc. The problem is, and I think it's because the entity is a stream, it clears out the body. So by the time the jaxb mapping to the beans happen, there is nothing to transform and I'm given a bad request response.
That didn't work but I wanted to throw it out there as a possibility if someone could get it working better.
Here is what I ended up doing, and it would be nice to not have to do it this way. I'm basically marshalling what was unmarshalled, in my service class.
final StringWriter st = new StringWriter();
try
{
final JAXBContext jaxbContext = JAXBContext.newInstance(full.classpath.and.classname.of.root.bean);
final Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(unmarshalled object, st);
} catch (final JAXBException je)
{
// TODO Auto-generated catch block
je.printStackTrace();
}
final String xml = st.toString();
So you can see - I basically take the object, the root bean that the body was unmarshalled to, and marshal it, giving the location of the annotated root bean to use in marhsalling.
It seems a bit redonkulous to have to marshal what was already unmarshalled, and if that is the response, maybe marshalled again on the way out. I would like a solution where I could grab a copy of the body before the unmarshalling happens. But in the meantime, this will have to work.
I ran into the same scenario and ended with similar conclusions, except I do it the other way around by getting it as a String and then marshal manually to avoid unnecessary JAXB work, e.g.:
String xmlString = request.getEntity(String.class);
Reader sReader = new StringReader(xmlString);
return (T)jaxbCtx.createUnmarshaller().unmarshal(sReader);

"Generic" #XmlRootElement?

I'm working against a very large API, most of whose return values look like:
<{APIMethodName}Resp>
<ResponseCode></ResponseCode>
<ResponseMessage></ResponseMessage>
</{APIMethodName}Resp>
Is there any sort of JAXB fu that will let me do this with just one class? I'm ok if JAXB ignores the root, just throws it away.
Thanks.
You could use the unmarshal method that take a class parameter. This causes the JAXB implementation to ignore the root element.

Checking for an attribute on a destination property inside a custom AutoMapper TypeConverter

I have a custom type converter that converts UTC DateTime properties to a company's local time (talked about here: Globally apply value resolver with AutoMapper).
I'd now like to only have this converter do its thing if the property on the view model is tagged with a custom DisplayInLocalTime attribute.
Inside the type converter, if I implement the raw ITypeConvert<TSource, TDestination> interface, I can check if the destination view model property being converted has the attribute:
public class LocalizedDateTimeConverter : ITypeConverter<DateTime, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
var shouldConvert = context.Parent.DestinationType
.GetProperty(context.MemberName)
.GetCustomAttributes(false)[0].GetType() == typeof(DisplayInLocalTimeAttribute);
if (shouldConvert) {
// rest of the conversion logic...
}
}
}
So this code works just fine (obviously there's more error checking and variables in there for readability).
My questions:
Is this the correct way to go about this? I haven't found anything Googling around or spelunking through the AutoMapper code base.
How would I unit test this? I can set the parent destination type on the ResolutionContext being passed in with a bit of funkiness, but can't set the member name as all implementors of IMemberAccessor are internal to AutoMapper. This, and the fact that it's super ugly to setup, makes me this isn't really supported or I'm going about it all wrong.
I'm using the latest TeamCity build of AutoMapper, BTW.
Don't unit test this, use an integration test. Just write a mapping test that actually calls AutoMapper, verifying that whatever use case this type converter is there to support works from the outside.
As a general rule, unit tests on extension points of someone else's API don't have as much value to me. Instead, I try to go through the front door and make sure that I've configured the extension point correctly as well.

Resources