问题
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>
回答1:
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
来源:https://stackoverflow.com/questions/28781737/restlet-complex-object-to-xml-serializaton