Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
295 views
in Technique[技术] by (71.8m points)

java - Restlet Complex Object to XML serializaton

I have restlet web service which returns response as xml. I'm using Jackson as binder. below is class I'm returning.

 import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;

    public class ApiResponse<T> implements Serializable {

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

        private int responseCode;
        private String reponseMessage;
        private List<T> body = new ArrayList<T>();

        public int getResponseCode() {
            return responseCode;
        }

        public void setResponseCode(int responseCode) {
            this.responseCode = responseCode;
        }

        public String getReponseMessage() {
            return reponseMessage;
        }

        public void setReponseMessage(String reponseMessage) {
            this.reponseMessage = reponseMessage;
        }

        public List<T> getBody() {
            return body;
        }

        public void setBody(List<T> body) {
            this.body = body;
        }

    }

And below is response of the service. Everything is almost good except that it puts as property names for nested objects the same as parents. It shows body for nested tag names but I expect it to be T template. Any ideas?

<ApiResponse>
    <responseCode>1</responseCode>
    <reponseMessage />
     <body>
        <body>
          <reportId>1</reportId>
          <reportName>name1</reportName>
        </body>
        <body>
          <reportId>2</reportId>
          <reportName>name2</reportName>
        </body>
     </body>
</ApiResponse>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is the default serialization with Jackson. However you can leverage custom serializer to improve this. This feature allows you to have the hand on the generated content within Jackson for a specific class. You can override the default strategy with your own and configure in a very fine manner what will be created.

Below a sample of such entity that generates content for the class SomeBean:

public class SomeBeanSerializer extends JsonSerializer<SomeBean> {
    @Override
    public void serialize(SomeBean bean, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
                  JsonProcessingException {
        jgen.writeStartObject();

        // Fields
        jgen.writeNumberField("id", bean.getId());
        (...)

        // Link
        String href = (...)
        HypermediaLink linkToSelf = new HypermediaLink();
        linkToSelf.setHref(href + bean.getId());
        linkToSelf.setRel("self");
        jgen.writeObjectField("hypermediaLink", linkToSelf);

        jgen.writeEndObject();
    }
}

Here is the way to configure this within Restlet:

JacksonConverter jacksonConverter = getRegisteredJacksonConverter();

if (jacksonConverter != null) {
    ObjectMapper objectMapper = jacksonConverter.getObjectMapper();
    SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null));
    module.addSerializer(SomeBean.class, new SomeBeanSerializer());
    objectMapper.registerModule(module);
}

This link could help you to see how to configure the Jackson converter of Restlet: https://templth.wordpress.com/2015/02/23/optimizing-restlet-server-applications/. It provides the content of the method getRegisteredJacksonConverter.

Edited: with version 2.3 of Restlet, something changes at this level. The object mapper is now brought by the JacksonRepresentation instead of the JacksonConverter itself. The object mapper is now instantiated for each representation of this kind. This means that you need to sub class these two elements to configure the custom serializer.

Here is the code of the class CustomJacksonRepresentation:

public class CustomJacksonRepresentation<T>
                extends JacksonRepresentation<T> {
    @Override
    public ObjectMapper getObjectMapper() {
        if (this.objectMapper == null) {
            this.objectMapper = createObjectMapper();
            SimpleModule module = new SimpleModule("MyModule",
                                    new Version(1, 0, 0, null));
            module.addSerializer(SomeBean.class,
                               new SomeBeanSerializer());
            objectMapper.registerModule(module);
        }
        return this.objectMapper;
    }
}

Here is the code of the class CustomJacksonConverter:

public class CustomJacksonConverter
                extends JacksonConverter {
    protected <T> JacksonRepresentation<T> create(
                        MediaType mediaType, T source) {
        return new CustomJacksonRepresentation<T>(
                                 mediaType, source);
    }

    protected <T> JacksonRepresentation<T> create(
              Representation source, Class<T> objectClass) {
        return new CustomJacksonRepresentation<T>(
                                 source, objectClass);
    }
}

This implemented, you need to replace the existing jackson converter that is automatically registered by Restlet. Here is the code to do that:

// Looking for the registered jackson converter
JacksonConverter jacksonConverter = null;
List<ConverterHelper> converters
         = Engine.getInstance().getRegisteredConverters();
for (ConverterHelper converterHelper : converters) {
    if (converterHelper instanceof JacksonConverter) {
        jacksonConverter = (JacksonConverter) converterHelper;
        break;
    }
}

// converters
Engine.getInstance().getRegisteredConverters().remove(
                                       jacksonConverter);
CustomJacksonConverter customJacksonConverter
                          = new CustomJacksonConverter();
Engine.getInstance().getRegisteredConverters().add(
                                 customJacksonConverter);

You can notice that the way to manage converters will be refactored in the version 3 of Restlet to make things more convenient to configure! ;-)

Hope it helps you, Thierry


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...