Robin Wieruch
Robin Wieruch

Reputation: 15898

Restlet - Post Object (even with Jaxb) doesnt work

I tried both: post a object as object or wrapped into JAXBElement. Nothing works for me.

//Create Object
Estate DTO estateOne = new EstateDTO("Hotel", "StreetOne", 1, 111111, "England", 1);

    ///setting up xstream
    XStream xstream = new XStream();
    xstream.processAnnotations(EstateResourceIF.class);
    xstream.processAnnotations(EstateDTO.class);
    xstream.autodetectAnnotations(true);

    xstream.setClassLoader(new EstateDTO().getClass().getClassLoader());
    xstream.alias("estateDTO", EstateDTO.class);
    xstream.alias("estateId", Integer.class);
            xstream.alias("estateName", String.class);

    //post object
    service.post(estateOne).write(System.out);

I even tried wrapping it up in JAXB:

 JAXBElement<EstateDTO> estate = new JAXBElement<EstateDTO>(new QName("estate"), EstateDTO.class, estateOne);

Same issues: I get:

                    Problem creating Marshaller

        javax.xml.bind.JAXBException: "com.bachelor.facade.object" doesnt contain ObjectFactory.class or jaxb.index
            at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:197)
            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 javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128)
            at javax.xml.bind.ContextFinder.find(ContextFinder.java:277)
            at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
            at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
            at org.restlet.ext.jaxb.JaxbRepresentation.getContext(JaxbRepresentation.java:97)
            at org.restlet.ext.jaxb.internal.Marshaller$1.initialValue(Marshaller.java:68)
            at org.restlet.ext.jaxb.internal.Marshaller$1.initialValue(Marshaller.java:64)
            at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:141)
            at java.lang.ThreadLocal.get(ThreadLocal.java:131)
            at org.restlet.ext.jaxb.internal.Marshaller.getMarshaller(Marshaller.java:163)
            at org.restlet.ext.jaxb.internal.Marshaller.marshal(Marshaller.java:216)
            at org.restlet.ext.jaxb.JaxbRepresentation.write(JaxbRepresentation.java:530)
            at org.restlet.engine.io.BioUtils$1.run(BioUtils.java:305)
            at org.restlet.service.TaskService$1$1.run(TaskService.java:132)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
            at java.util.concurrent.FutureTask.run(FutureTask.java:138)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:662)
        Unable to locate marshaller.
        JAXB marshalling error caught.

        javax.xml.bind.JAXBException: Unable to locate marshaller.
            at org.restlet.ext.jaxb.internal.Marshaller.getMarshaller(Marshaller.java:166)
            at org.restlet.ext.jaxb.internal.Marshaller.marshal(Marshaller.java:216)
            at org.restlet.ext.jaxb.JaxbRepresentation.write(JaxbRepresentation.java:530)
            at org.restlet.engine.io.BioUtils$1.run(BioUtils.java:305)
            at org.restlet.service.TaskService$1$1.run(TaskService.java:132)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
            at java.util.concurrent.FutureTask.run(FutureTask.java:138)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:662)
        Problem creating Marshaller

        javax.xml.bind.JAXBException: "failure" doesnt contain ObjectFactory.class or jaxb.index
            at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:197)
            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 javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128)
            at javax.xml.bind.ContextFinder.find(ContextFinder.java:277)
            at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
            at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
            at org.restlet.ext.jaxb.JaxbRepresentation.getContext(JaxbRepresentation.java:97)
            at org.restlet.ext.jaxb.internal.Marshaller$1.initialValue(Marshaller.java:68)
            at org.restlet.ext.jaxb.internal.Marshaller$1.initialValue(Marshaller.java:64)
            at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:141)
            at java.lang.ThreadLocal.get(ThreadLocal.java:131)
            at org.restlet.ext.jaxb.internal.Marshaller.getMarshaller(Marshaller.java:163)
            at org.restlet.ext.jaxb.internal.Marshaller.marshal(Marshaller.java:216)
            at org.restlet.ext.jaxb.JaxbRepresentation.write(JaxbRepresentation.java:538)
            at org.restlet.engine.io.BioUtils$1.run(BioUtils.java:305)
            at org.restlet.service.TaskService$1$1.run(TaskService.java:132)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
            at java.util.concurrent.FutureTask.run(FutureTask.java:138)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
            at java.lang.Thread.run(Thread.java:662)
        Unable to locate marshaller.

Even if I try it with:

EstateResourceIF estateResource = service.wrap(EstateResourceIF.class);

    List<Preference<MediaType>> acceptedMediaTypes = new ArrayList<Preference<MediaType>>();
    acceptedMediaTypes.add(new Preference(MediaType.APPLICATION_JSON));
    service.getClientInfo().setAcceptedMediaTypes(acceptedMediaTypes);

    estateResource.postEstate(estateOne);

Some more facts for solution:

EstateDTO class:

    @XmlRootElement
    //JAX-RS supports an automatic mapping from JAXB annotated class to XML and JSON
    @XmlAccessorType(XmlAccessType.FIELD)
    public class EstateDTO implements Serializable{

        /**
         * 
         */
        private static final long serialVersionUID = -8545841080597549468L;

        @XmlElement(name="estateId")
        private String estateId;
        @XmlElement(name="owner")
        private String owner;
        @XmlElement(name="estateName")
        private String estateName;
        @XmlElement(name="street")
        private String street;
        @XmlElement(name="number")
        private int number;
        @XmlElement(name="extraAddressLine")
        private String extraAddressLine;
        @XmlElement(name="zip")
        private int zip;
        @XmlElement(name="country")
        private String country;

        private int space;
        private List<String> tenants = new ArrayList<String>();

        public EstateDTO() {

        }

        public EstateDTO(String estateName, String street, int number, int zip, String country, int space) {
            this.estateName = estateName;
            this.street = street;
            this.number = number;
            this.zip = zip;
            this.country = country;
            this.space = space;
        }

EDIT:

Server Sided Post

        @POST
        @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Response postEstate(EstateDTO c) {
            //EstateDTO c = estate.getValue();
            System.out.println(c);
            String generatedId = generateID();
            c.setEstateId(generatedId);
            c.setOwner(sec.getUserPrincipal().getName());
            return postAndGetResponse(c);
        }

the system out on cosole says

 EstateDTO [estateId=null, owner=null, estateName=null, street=null, number=0, extraAddressLine=null, zip=0, country=null, space=0, tenants=[]]

postAndGetResponse Method:

        private Response postAndGetResponse(EstateDTO estate) {
            Response res;
            System.out.println(estate);
            if(EstateDAO.instance.getEstateDao().containsKey(estate.getEstateId())) {
                res = Response.serverError().status(409).build();
            } else {
                res = Response.created(UriBuilder.fromUri(uriInfo.getAbsolutePath() + "/" + estate.getEstateId()).build()).entity(estate).build();
                EstateDAO.instance.getEstateDao().put(estate.getEstateId(), estate);
            }
            return res;
        }

Dependencies:

                    <dependency>
                <groupId>org.restlet.jee</groupId>
                <artifactId>org.restlet</artifactId>
                <version>${restlet.version}</version>
        </dependency>
        <dependency>  
           <groupId>org.restlet.jee</groupId>  
           <artifactId>org.restlet.ext.xstream</artifactId>  
           <version>${restlet.version}</version>  
        </dependency>

        <dependency>  
           <groupId>org.restlet.jee</groupId>  
           <artifactId>org.restlet.ext.jackson</artifactId>  
           <version>${restlet.version}</version>  
        </dependency>

        <dependency>  
           <groupId>org.restlet.jee</groupId>  
           <artifactId>org.restlet.ext.jaxb</artifactId>  
           <version>${restlet.version}</version>  
        </dependency>

        <dependency>  
           <groupId>org.restlet.jee</groupId>  
           <artifactId>org.restlet.ext.json</artifactId>  
           <version>${restlet.version}</version>  
        </dependency>

        <dependency>  
           <groupId>org.restlet.jee</groupId>  
           <artifactId>org.restlet.ext.xml</artifactId>  
           <version>${restlet.version}</version>  
        </dependency>

        <!-- Jersey JAXB -->
         <!--   <dependency>
               <groupId>com.sun.jersey</groupId>
               <artifactId>jersey-json</artifactId>
               <version>1.12</version>
           </dependency>-->

Upvotes: 1

Views: 813

Answers (1)

bdoughan
bdoughan

Reputation: 149017

Your JAXB mappings appear to be correct, and since you have mapped your class with @XmlRootElement you do not need to wrap the object in a JAXBElement. I also double checked and your XStream mappings appear to match your JAXB mappings (see below). My current guess is the problem lies in your post method. Could you add the post method from the service to your question?

EstateDTO

I have simplified your EstateDTO class by taking advantage of JAXB being configuration by exception. This means you only need to add annotations where the behaviour differs from the default mapping.

package forum11410653;

import java.io.Serializable;
import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
//JAX-RS supports an automatic mapping from JAXB annotated class to XML and JSON
@XmlAccessorType(XmlAccessType.FIELD)
public class EstateDTO implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = -8545841080597549468L;

    private String estateId;
    private String owner;
    private String estateName;
    private String street;
    private int number;
    private String extraAddressLine;
    private int zip;
    private String country;

    private int space;
    private List<String> tenants = new ArrayList<String>();

    public EstateDTO() {
    }

    public EstateDTO(String estateName, String street, int number, int zip, String country, int space) {
        this.estateName = estateName;
        this.street = street;
        this.number = number;
        this.zip = zip;
        this.country = country;
        this.space = space;
    }

}

Demo

Below is some standalone JAXB code to ensure that everything works.

package forum11410653;

import java.io.*;
import javax.xml.bind.*;
import com.thoughtworks.xstream.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        EstateDTO estateDTO = new EstateDTO("Hotel", "StreetOne", 1, 111111,
                "England", 1);

        // setting up xstream
        XStream xstream = new XStream();
        xstream.processAnnotations(EstateDTO.class);
        xstream.autodetectAnnotations(true);

        xstream.setClassLoader(new EstateDTO().getClass().getClassLoader());
        xstream.alias("estateDTO", EstateDTO.class);
        xstream.alias("estateId", Integer.class);
        xstream.alias("estateName", String.class);
        StringWriter writer = new StringWriter();
        xstream.toXML(estateDTO, writer);

        String xml = writer.toString();
        System.out.println(xml);

        // setting up JAXB
        JAXBContext jc = JAXBContext.newInstance(EstateDTO.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        EstateDTO unmarshalled = (EstateDTO) unmarshaller
                .unmarshal(new StringReader(xml));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(unmarshalled, System.out);
    }

}

Output

As you can see estateName, street, and country are populated.

<estateDTO>
  <estateName>Hotel</estateName>
  <street>StreetOne</street>
  <number>1</number>
  <zip>111111</zip>
  <country>England</country>
  <space>1</space>
  <tenants/>
</estateDTO>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<estateDTO>
    <estateName>Hotel</estateName>
    <street>StreetOne</street>
    <number>1</number>
    <zip>111111</zip>
    <country>England</country>
    <space>1</space>
    <tenants></tenants>
</estateDTO>

Upvotes: 1

Related Questions