4

In my JAX-RS project (Jersey) I'm having a problem getting one of the JAXB-annotated objects marshalled to JSON. Here is the error message I see in the logs:

SEVERE: Internal server error javax.ws.rs.WebApplicationException: javax.xml.bind.JAXBException: class com.dnb.applications.webservice.mobile.view.CompaniesAndLocations nor any of its super class is known to this context.

Does this point to any specific problem? My resource has a method like this:

@Path("/name/{companyname}/location/{location}")
@Produces("application/json; charset=UTF-8;")
@Consumes("application/json")
@POST
public Viewable findCompanyByCompanyNameAndLocationAsJSON(@PathParam("companyname") String companyName,
        @PathParam("location") String location, CriteriaView criteria) {
    criteria = criteria != null ? criteria : new CriteriaView();
    criteria.getKeywords().setCompanyName(companyName);
    return getCompanyListsHandler().listsByCompanyNameAndLocation(criteria, location);
}

Viewable is an empty interface. The above method returns an object of type CompaniesAndLocations, defined as follows:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "companiesAndLocations", propOrder = { "count", "normalizedLocations", "companyList", "companyMap", "modifiers",
        "modifiersMap", "companyCount", "navigators" })
public class CompaniesAndLocations extends BaseCompanies implements Viewable {

    @XmlElement(name = "normalizedLocations", required = false)
    protected List<NormalizedLocation> normalizedLocations;

    public List<NormalizedLocation> getNormalizedLocations() {
        if (normalizedLocations == null) {
            normalizedLocations = new ArrayList<NormalizedLocation>();
        }
        return normalizedLocations;
    }

}

BaseCompanies defines a number of other fields:

@XmlTransient
public abstract class BaseCompanies {

    @XmlElement(name = "modifiers", required = false)
    private List<Modifiers> modifiers;
....

I should add that I'm deviating slightly from the approach used by other working code in the app. The other resource methods get their objects from an ObjectFactory that is annotated with @XmlRegistry. I don't think this is necessary, though. I have seen other code that directly instantiates the JAXB-annotated POJO'swithout using the ObjectFactory factory.

Any ideas?

1 Answer 1

7

JAX-RS does what it can to bootstrap a JAXBContext, but it can't always reach all the classes it needs to know about. For this reason you can implement a ContextResolver. This gives you full control over how the JAXBContext is created. Below is an example of how it might look:

package org.example.order;

import javax.ws.rs.Produces;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.eclipse.persistence.jaxb.JAXBContextFactory;

@Provider
@Produces({"application/xml", "application/json"})
public class PurchaseOrderContextResolver implements ContextResolver<JAXBContext> {

    private JAXBContext jaxbContext;

    public PurchaseOrderContextResolver() {
        try {
            // Bootstrap your JAXBContext will all necessary classes
            jaxbContext = JAXBContext.newInstance(PurchaseOrder.class);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JAXBContext getContext(Class<?> clazz) {
        if(PurchaseOrder.class == clazz) {
            return jaxbContext;
        }
        return null;
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Cool, thanks, this looks useful. Is this essentially what the @XmlRegistry annotation does under the covers?
No @XmlRegistry is something else. The purpose of the ContextResolver is give the developer full control over how the JAXBContext is bootstrapped. Without it a JAX-RS implementation will bootstrap the JAXBContext starting from the parameter types, and traverse the graph pulling in more types. Often times this gets everything you need, but things like inheritance and un-typed lists can cause types to be missed. The @XmlSeeAlso annotation can also be useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.