Including null elements in JSON RESTful JSON API output with JAXB

I have a class that I would like to open through the RESTful Jersey API. It looks something like this:

@XmlRootElement public class Data { public String firstName; public String lastName; } 

My problem is that these fields can be null, in which case the field is output from JSON output. I would like all fields to be present regardless of their value. For example, if lastName is NULL, the JSON output will look like this:

 { "firstName" : "Oleksi" } 

instead of what i want:

 { "firstName" : "Oleksi", "lastName" : null } 

I have a JAXBContextResolver (implementation of ContextResolver) that looks like this:

 @Provider public class JAXBContextResolver implements ContextResolver<JAXBContext> { // internal state private final JAXBContext context; private final Set<Class> types; private final Class[] cTypes = { Data.class }; public JAXBContextResolver() throws Exception { types = new HashSet(Arrays.asList(cTypes)); context = new JSONJAXBContext(JSONConfiguration.natural().humanReadableFormatting(true).build(), cTypes); } @Override public JAXBContext getContext(Class<?> objectType) { return (types.contains(objectType)) ? context : null; } } 

I tried to figure out how to get the desired result for a while, but I was out of luck. I am open to testing other ContextResolvers / Serializers, but I could not find one that works, so the code examples would be nice.

+4
source share
2 answers

For EclipseLink JAXB (MOXy) JSON binding, the correct mapping will be as follows. You can try with your provider to find out if this will work:

 @XmlRootElement public class Data { @XmlElement(nillable=true) public String firstName; @XmlElement(nillable=true) public String lastName; } 

Additional Information


UPDATE 2

EclipseLink 2.4 includes MOXyJsonProvider , which is an implementation of MessageBodyReader / MessageBodyWriter that you can use directly to use the MOXy JSON binding

UPDATE 1

The following MessageBodyReader / MessageBodyWriter may work better for you:

 import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.*; import javax.xml.transform.stream.StreamSource; import javax.ws.rs.*; import javax.ws.rs.core.*; import javax.ws.rs.ext.*; import javax.xml.bind.*; import org.eclipse.persistence.jaxb.JAXBContextFactory; @Provider @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class MOXyJSONProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object>{ @Context protected Providers providers; public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; } public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { try { Class<?> domainClass = getDomainClass(genericType); Unmarshaller u = getJAXBContext(domainClass, mediaType).createUnmarshaller(); u.setProperty("eclipselink.media-type", mediaType.toString()); u.setProperty("eclipselink.json.include-root", false); return u.unmarshal(new StreamSource(entityStream), domainClass).getValue(); } catch(JAXBException jaxbException) { throw new WebApplicationException(jaxbException); } } public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return true; } public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { try { Class<?> domainClass = getDomainClass(genericType); Marshaller m = getJAXBContext(domainClass, mediaType).createMarshaller(); m.setProperty("eclipselink.media-type", mediaType.toString()); m.setProperty("eclipselink.json.include-root", false); m.marshal(object, entityStream); } catch(JAXBException jaxbException) { throw new WebApplicationException(jaxbException); } } public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } private JAXBContext getJAXBContext(Class<?> type, MediaType mediaType) throws JAXBException { ContextResolver<JAXBContext> resolver = providers.getContextResolver(JAXBContext.class, mediaType); JAXBContext jaxbContext; if(null == resolver || null == (jaxbContext = resolver.getContext(type))) { return JAXBContextFactory.createContext(new Class[] {type}, null); } else { return jaxbContext; } } private Class<?> getDomainClass(Type genericType) { if(genericType instanceof Class) { return (Class<?>) genericType; } else if(genericType instanceof ParameterizedType) { return (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0]; } else { return null; } } } 
+10
source

Java null is JavaScript undefined. If you want to convert Java null to JavaScript null, you need to consult your transform library.

0
source

Source: https://habr.com/ru/post/905235/


All Articles