I'm working with a serialization model based on @JsonView
. I normally configure jackson with a ContextResolver
like this:
@Override
public ObjectMapper getContext(Class<?> aClass) {
// enable a view by default, else Views are not processed
Class view = Object.class;
if (aClass.getPackage().getName().startsWith("my.company.entity")) {
view = getViewNameForClass(aClass);
}
objectMapper.setSerializationConfig(
objectMapper.getSerializationConfig().withView(view));
return objectMapper;
}
This works fine if I serialize single entities. However, for certain use cases I want to serialize lists of my entities using the same view as for single entities. In this case, aClass
is ArrayList
, so the usual logic doesn't help much.
So I'm looking for a way to tell Jackson which view to use. Ideally, I'd write:
@GET @Produces("application/json; charset=UTF-8")
@JsonView(JSONEntity.class)
public List<T> getAll(@Context UriInfo uriInfo) {
return getAll(uriInfo.getQueryParameters());
}
And have that serialized under the view JSONEntity
. Is this possible with RestEasy? If not, how can I emulate that?
Edit: I know I can do the serialization myself:
public String getAll(@Context UriInfo info, @Context Providers factory) {
List<T> entities = getAll(info.getQueryParameters());
ObjectMapper mapper = factory.getContextResolver(
ObjectMapper.class, MediaType.APPLICATION
).getContext(entityClass);
return mapper.writeValueAsString(entities);
}
However, this is clumsy at best and defeats the whole idea of having the framework deal with this boilerplate.
The JsonView annotation can be used to include/exclude a property during the serialization and deserialization process dynamically. We need to configure an ObjectMapper class to include the type of view used for writing a JSON from Java object using the writerWithView() method.
ObjectMapper; ObjectMapper objectMapper = new ObjectMapper(); objectMapper. configure(DeserializationFeature. FAIL_ON_UNKNOWN_PROPERTIES, false); This will now ignore unknown properties for any JSON it's going to parse, You should only use this option if you can't annotate a class with @JsonIgnoreProperties annotation.
To ignore individual properties, use the [JsonIgnore] attribute. You can specify conditional exclusion by setting the [JsonIgnore] attribute's Condition property. The JsonIgnoreCondition enum provides the following options: Always - The property is always ignored.
Turns out, it is possible to simply annotate a specific endpoint with @JsonView
(just as in my question) and jackson will use this view. Who would have guessed.
You can even do this in the generic way (more context in my other question), but that ties me to RestEasy:
@Override
public void writeTo(Object value, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHd,
OutputStream out) throws IOException {
Class view = getViewFromType(type, genericType);
ObjectMapper mapper = locateMapper(type, mediaType);
Annotation[] myAnn = Arrays.copyOf(annotations, annotations.length + 1);
myAnn[annotations.length] = new JsonViewQualifier(view);
super.writeTo(value, type, genericType, myAnn, mediaType, httpHd, out);
}
private Class getViewFromType(Class<?> type, Type genericType) {
// unwrap collections
Class target = org.jboss.resteasy.util.Types.getCollectionBaseType(
type, genericType);
target = target != null ? target : type;
try {
// use my mix-in as view class
return Class.forName("example.jackson.JSON" + target.getSimpleName());
} catch (ClassNotFoundException e) {
LOGGER.info("No view found for {}", target.getSimpleName());
}
return Object.class;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With