Skip to content

Extract default jackson object mappers in ObjectMappers class for allowi... #992

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: 2.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,17 @@

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;

import org.restlet.data.MediaType;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.dataformat.csv.CsvFactory;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

/**
* Representation based on the Jackson library. It can serialize and deserialize
Expand All @@ -79,17 +71,19 @@ public class JacksonRepresentation<T> extends OutputRepresentation {
* True for expanding entity references when parsing XML representations;
* default value provided by system property
* "org.restlet.ext.xml.expandingEntityRefs", false by default.
* @deprecated Use {@link org.restlet.ext.jackson.ObjectMappers.XmlMapperFactory#XML_EXPANDING_ENTITY_REFS}
*/
public static boolean XML_EXPANDING_ENTITY_REFS = Boolean
.getBoolean("org.restlet.ext.xml.expandingEntityRefs");
@Deprecated
public static boolean XML_EXPANDING_ENTITY_REFS = ObjectMappers.XmlMapperFactory.XML_EXPANDING_ENTITY_REFS;

/**
* True for validating DTD documents when parsing XML representations;
* default value provided by system property
* "org.restlet.ext.xml.validatingDtd", false by default.
* @deprecated Use {@link org.restlet.ext.jackson.ObjectMappers.XmlMapperFactory#XML_VALIDATING_DTD}
*/
public static boolean XML_VALIDATING_DTD = Boolean
.getBoolean("org.restlet.ext.xml.validatingDtd");
@Deprecated
public static boolean XML_VALIDATING_DTD = ObjectMappers.XmlMapperFactory.XML_VALIDATING_DTD;

/** The modifiable Jackson CSV schema. */
private CsvSchema csvSchema;
Expand Down Expand Up @@ -201,46 +195,31 @@ protected CsvSchema createCsvSchema(CsvMapper csvMapper) {
* @return The Jackson object mapper.
*/
protected ObjectMapper createObjectMapper() {
ObjectMapper result = null;

if (MediaType.APPLICATION_JSON.isCompatible(getMediaType())) {
JsonFactory jsonFactory = new JsonFactory();
jsonFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new ObjectMapper(jsonFactory);
return ObjectMappers.getDefaultJsonMapperFactory().newObjectMapper();
} else if (MediaType.APPLICATION_JSON_SMILE
.isCompatible(getMediaType())) {
SmileFactory smileFactory = new SmileFactory();
smileFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new ObjectMapper(smileFactory);
return ObjectMappers.getDefaultJsonSmileMapperFactory().newObjectMapper();
} else if (MediaType.APPLICATION_XML.isCompatible(getMediaType())
|| MediaType.TEXT_XML.isCompatible(getMediaType())) {
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
isExpandingEntityRefs());
xif.setProperty(XMLInputFactory.SUPPORT_DTD,
isExpandingEntityRefs());
xif.setProperty(XMLInputFactory.IS_VALIDATING, isValidatingDtd());
XMLOutputFactory xof = XMLOutputFactory.newFactory();
XmlFactory xmlFactory = new XmlFactory(xif, xof);
xmlFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new XmlMapper(xmlFactory);
ObjectMapper objectMapper = ObjectMappers.getDefaultXmlMapperFactory().newObjectMapper();
//for backward compatibility (deprecated)
if (objectMapper instanceof XmlMapper) {
XmlMapper xmlMapper = (XmlMapper) objectMapper;
XMLInputFactory xif = xmlMapper.getFactory().getXMLInputFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isExpandingEntityRefs());
xif.setProperty(XMLInputFactory.SUPPORT_DTD, isExpandingEntityRefs());
xif.setProperty(XMLInputFactory.IS_VALIDATING, isValidatingDtd());
}
return objectMapper;
} else if (MediaType.APPLICATION_YAML.isCompatible(getMediaType())
|| MediaType.TEXT_YAML.isCompatible(getMediaType())) {
YAMLFactory yamlFactory = new YAMLFactory();
yamlFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new ObjectMapper(yamlFactory);
return ObjectMappers.getDefaultYamlMapperFactory().newObjectMapper();
} else if (MediaType.TEXT_CSV.isCompatible(getMediaType())) {
CsvFactory csvFactory = new CsvFactory();
csvFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new CsvMapper(csvFactory);
return ObjectMappers.getDefaultCsvMapperFactory().newObjectMapper();
} else {
JsonFactory jsonFactory = new JsonFactory();
jsonFactory.configure(Feature.AUTO_CLOSE_TARGET, false);
result = new ObjectMapper(jsonFactory);
return ObjectMappers.getDefaultJsonMapperFactory().newObjectMapper();
}

result.setSerializationInclusion(Include.NON_NULL);
return result;
}

/**
Expand Down Expand Up @@ -372,7 +351,10 @@ public ObjectWriter getObjectWriter() {
* the value of this is set to true.
*
* @return True if the parser will expand entity reference nodes.
* @deprecated configure it globally in {@link ObjectMappers.XmlMapperFactory}
* or override {@link #createObjectMapper()} to configure it for an instance only.
*/
@Deprecated
public boolean isExpandingEntityRefs() {
return expandingEntityRefs;
}
Expand All @@ -382,7 +364,10 @@ public boolean isExpandingEntityRefs() {
* against an XML schema if one is referenced within the contents.
*
* @return True if the schema-based validation is enabled.
* @deprecated configure it globally in {@link ObjectMappers.XmlMapperFactory}
* or override {@link #createObjectMapper()} to configure it for an instance only.
*/
@Deprecated
public boolean isValidatingDtd() {
return validatingDtd;
}
Expand All @@ -403,7 +388,10 @@ public void setCsvSchema(CsvSchema csvSchema) {
*
* @param expandEntityRefs
* True if the parser will expand entity reference nodes.
* @deprecated configure it globally in {@link ObjectMappers.XmlMapperFactory}
* or override {@link #createObjectMapper()} to configure it for an instance only.
*/
@Deprecated
public void setExpandingEntityRefs(boolean expandEntityRefs) {
this.expandingEntityRefs = expandEntityRefs;
}
Expand Down Expand Up @@ -464,7 +452,10 @@ public void setObjectWriter(ObjectWriter objectWriter) {
*
* @param validating
* The new validation flag to set.
* @deprecated configure it globally in {@link ObjectMappers.XmlMapperFactory}
* or override {@link #createObjectMapper()} to configure it for an instance only.
*/
@Deprecated
public void setValidatingDtd(boolean validating) {
this.validatingDtd = validating;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package org.restlet.ext.jackson;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvFactory;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;

/**
* List of default object mappers for each supported media type.
*
* Each default object mappers could be overridden for customize the default behaviour.
*
* @author Manuel Boillod
*/
public class ObjectMappers {

public static JsonInclude.Include DEFAULT_SERIALIZATION_INCLUSION = JsonInclude.Include.ALWAYS;

/**
* Simple {@link ObjectMapper} factory
*/
public static interface ObjectMapperFactory {
/**
* Returns a new instance of {@link ObjectMapper}.
*/
ObjectMapper newObjectMapper();
}

/** Default object mapper for JSON media type */
private static ObjectMapperFactory DEFAULT_JSON_MAPPER_FACTORY = new JsonMapperFactory();
/** Default object mapper for JSON SMILE media type */
private static ObjectMapperFactory DEFAULT_JSON_SMILE_MAPPER_FACTORY = new JsonSmileMapperFactory();
/** Default object mapper for XML media type */
private static ObjectMapperFactory DEFAULT_XML_MAPPER_FACTORY = new XmlMapperFactory();
/** Default object mapper for YAML media type */
private static ObjectMapperFactory DEFAULT_YAML_MAPPER_FACTORY = new YamlMapperFactory();
/** Default object mapper for CSV media type */
private static ObjectMapperFactory DEFAULT_CSV_MAPPER_FACTORY = new CsvMapperFactory();

/** Returns the default object mapper for JSON media type */
public static ObjectMapperFactory getDefaultJsonMapperFactory() {
return DEFAULT_JSON_MAPPER_FACTORY;
}

/** Define the default object mapper for JSON media type */
public static void setDefaultJsonMapperFactory(ObjectMapperFactory DEFAULT_JSON_MAPPER_FACTORY) {
ObjectMappers.DEFAULT_JSON_MAPPER_FACTORY = DEFAULT_JSON_MAPPER_FACTORY;
}

/** Returns the default object mapper for JSON SMILE media type */
public static ObjectMapperFactory getDefaultJsonSmileMapperFactory() {
return DEFAULT_JSON_SMILE_MAPPER_FACTORY;
}

/** Define the default object mapper for JSON SMILE media type */
public static void setDefaultJsonSmileMapperFactory(ObjectMapperFactory DEFAULT_JSON_SMILE_MAPPER_FACTORY) {
ObjectMappers.DEFAULT_JSON_SMILE_MAPPER_FACTORY = DEFAULT_JSON_SMILE_MAPPER_FACTORY;
}

/** Returns the default object mapper for XML media type */
public static ObjectMapperFactory getDefaultXmlMapperFactory() {
return DEFAULT_XML_MAPPER_FACTORY;
}

/** Define the default object mapper for XML media type */
public static void setDefaultXmlMapperFactory(ObjectMapperFactory DEFAULT_XML_MAPPER_FACTORY) {
ObjectMappers.DEFAULT_XML_MAPPER_FACTORY = DEFAULT_XML_MAPPER_FACTORY;
}

/** Returns the default object mapper for YAML media type */
public static ObjectMapperFactory getDefaultYamlMapperFactory() {
return DEFAULT_YAML_MAPPER_FACTORY;
}

/** Define the default object mapper for YAML media type */
public static void setDefaultYamlMapperFactory(ObjectMapperFactory DEFAULT_YAML_MAPPER_FACTORY) {
ObjectMappers.DEFAULT_YAML_MAPPER_FACTORY = DEFAULT_YAML_MAPPER_FACTORY;
}

/** Returns the default object mapper for CSV media type */
public static ObjectMapperFactory getDefaultCsvMapperFactory() {
return DEFAULT_CSV_MAPPER_FACTORY;
}

/** Define the default object mapper for CSV media type */
public static void setDefaultCsvMapperFactory(ObjectMapperFactory DEFAULT_CSV_MAPPER_FACTORY) {
ObjectMappers.DEFAULT_CSV_MAPPER_FACTORY = DEFAULT_CSV_MAPPER_FACTORY;
}

/** Default {@link ObjectMapperFactory} for JSON media type */
public static class JsonMapperFactory implements ObjectMapperFactory {
@Override
public ObjectMapper newObjectMapper() {
JsonFactory jsonFactory = new JsonFactory();
jsonFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
objectMapper.setSerializationInclusion(DEFAULT_SERIALIZATION_INCLUSION);
return objectMapper;
}
}

/** Default {@link ObjectMapperFactory} for JSON SMILE media type */
public static class JsonSmileMapperFactory implements ObjectMapperFactory {
@Override
public ObjectMapper newObjectMapper() {
JsonFactory jsonFactory = new JsonFactory();
jsonFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
objectMapper.setSerializationInclusion(DEFAULT_SERIALIZATION_INCLUSION);
return objectMapper;
}
}

/** Default {@link ObjectMapperFactory} for XML media type */
public static class XmlMapperFactory implements ObjectMapperFactory {
/**
* True for expanding entity references when parsing XML representations;
* default value provided by system property
* "org.restlet.ext.xml.expandingEntityRefs", false by default.
*/
public static boolean XML_EXPANDING_ENTITY_REFS = Boolean
.getBoolean("org.restlet.ext.xml.expandingEntityRefs");

/**
* True for validating DTD documents when parsing XML representations;
* default value provided by system property
* "org.restlet.ext.xml.validatingDtd", false by default.
*/
public static boolean XML_VALIDATING_DTD = Boolean
.getBoolean("org.restlet.ext.xml.validatingDtd");

@Override
public ObjectMapper newObjectMapper() {
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, XML_EXPANDING_ENTITY_REFS);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, XML_EXPANDING_ENTITY_REFS);
xif.setProperty(XMLInputFactory.IS_VALIDATING, XML_VALIDATING_DTD);
XMLOutputFactory xof = XMLOutputFactory.newFactory();
XmlFactory xmlFactory = new XmlFactory(xif, xof);
xmlFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
ObjectMapper objectMapper = new XmlMapper(xmlFactory);
objectMapper.setSerializationInclusion(DEFAULT_SERIALIZATION_INCLUSION);
return objectMapper;
}
}

/** Default {@link ObjectMapperFactory} for YAML media type */
public static class YamlMapperFactory implements ObjectMapperFactory {
@Override
public ObjectMapper newObjectMapper() {
YAMLFactory yamlFactory = new YAMLFactory();
yamlFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
ObjectMapper objectMapper = new ObjectMapper(yamlFactory);
objectMapper.setSerializationInclusion(DEFAULT_SERIALIZATION_INCLUSION);
return objectMapper;
}
}

/** Default {@link ObjectMapperFactory} for CSV media type */
public static class CsvMapperFactory implements ObjectMapperFactory {
@Override
public ObjectMapper newObjectMapper() {
CsvFactory csvFactory = new CsvFactory();
csvFactory.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
ObjectMapper objectMapper = new CsvMapper(csvFactory);
objectMapper.setSerializationInclusion(DEFAULT_SERIALIZATION_INCLUSION);
return objectMapper;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ public void testStatusSerialization() throws IOException {
Status expectedStatus = Status.CLIENT_ERROR_BAD_REQUEST;
HashMap<String, Object> expectedRepresentationMap = new LinkedHashMap<>();
expectedRepresentationMap.put("code", expectedStatus.getCode());
expectedRepresentationMap.put("contactEmail", null);
expectedRepresentationMap.put("description",
expectedStatus.getDescription());
expectedRepresentationMap.put("homeRef", null);
expectedRepresentationMap.put("reasonPhrase",
expectedStatus.getReasonPhrase());
expectedRepresentationMap.put("uri",
Expand All @@ -122,6 +124,7 @@ public void testSerializedException() throws IOException {

// verify
HashMap<String, Object> expectedRepresentationMap = new LinkedHashMap<>();
expectedRepresentationMap.put("cause", null);
expectedRepresentationMap.put("stackTrace", exception.getStackTrace());
expectedRepresentationMap.put("value", 50);
expectedRepresentationMap.put("message", "test message");
Expand Down