11

How to remove the type from the JSON output that I have. I have a class/bean that contains output of a REST service.I'm using jersey-media-moxy to do the conversion.

The service

@Resource
public interface MyBeanResource
{
    @GET
    @Path("/example")
    @Produces( MediaType.APPLICATION_JSON )
    public Bean getBean();
}

The Bean

@XmlRootElement
class Bean
{
   String a;
}  

I want to add some functionality (for initializing the bean using the constructor)

class BeanImpl extends Bean
{
    BeanImpl(OtherClass c)
    {
        a = c.toString()
    }
}

The outputted JSON is:

{type:"beanImpl", a:"somevalue"}

I do not want the type in my JSON. How can I configure this?

Kundan Atre
  • 3,853
  • 5
  • 26
  • 39
Rob Audenaerde
  • 19,195
  • 10
  • 76
  • 121

5 Answers5

17

I get the same error when I extend a class and generate JSON -- but only for a top-level (root) class. As a workaround, I annotate my subclass with @XmlType(name=""), which prevents the generated type property from appearing in my JSON.

Blaise, I'm not sure why this works. Any thoughts?

Dennis Mitchell
  • 201
  • 1
  • 4
  • 2
    With the name attribute you probably override what would be written in the type property. Since you defined it as empty, Jersey skips the property completely. – kazanaki Jun 08 '16 at 09:44
3

MOXy will add a type indicator to differentiate between the different subtypes. This however will only happen if MOXy is aware of the subtypes (it isn't by default).

Demo Code

Demo

Below is the equivalent code that Jersey will call on MOXy.

import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;

public class Demo {

    public static void main(String[] args) throws Exception {
        MOXyJsonProvider mjp = new MOXyJsonProvider();

        BeanImpl beanImpl = new BeanImpl(new OtherClass());
        mjp.writeTo(beanImpl, Bean.class, Bean.class, null, null, null, System.out);

    }

}

Output

{}

Possible Problem?

Do you potentially have an @XmlSeeAlso annotation on your real Bean class?

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlSeeAlso(BeanImpl.class)
class Bean
{
   String a;
}  

Then the output will be (assuming BeanImpl also has a no-arg constructor):

{"type":"beanImpl"}
bdoughan
  • 147,609
  • 23
  • 300
  • 400
1

You can build a custom message body writer .

@Provider
@Produces({
   MediaType.APPLICATION_JSON
})
public class BeanBodyWriter implements MessageBodyWriter<Bean> {

    @Override
    public long getSize(Bean t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // Called before isWriteable by Jersey. Return -1 if you don't the size yet. 
        return -1;
    }

    @Override
    public boolean isWriteable(Class<?> clazz, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // Check that the passed class by Jersey can be handled by our message body writer
        return Bean.class.isAssignableFrom(clazz);
    }

    @Override
    public void writeTo(Bean t, Class<?> clazz, Type genericType, Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders, OutputStream out) throws IOException, WebApplicationException {

        // Call your favorite JSON library to generate the JSON code and remove the unwanted fields...
        String json = "...";

        out.write(json.getBytes("UTF-8"));
    }
}
Stephan
  • 41,764
  • 65
  • 238
  • 329
  • 1
    That seems like overkill? – Rob Audenaerde Jan 13 '14 at 12:25
  • @RobAu Check my update, what is left is writing the `writeTo` method. – Stephan Jan 13 '14 at 12:47
  • Hi Alex, thanks for elaborating. I still think it seems 'too much work' for the problem, indicating the solution will work, but is harder to maintain, etc. My alternative is a rewrite to a FactoryPattern and remove the subclassed-beans. I hoped for an eiasier annotation/configuration based solution. – Rob Audenaerde Jan 13 '14 at 12:49
0

Use this to generate JSON and you won't have that problem:

<dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-json-provider</artifactId>
    <version>2.3.3</version>
</dependency>
0

I used a Jersey specific Jackson package in a slightly different case, it worked. Detailed configuration is described in Jersy document. In my case, I used a generic type field in an @XmlRootElement class. MOXy added a type in the JSON output. I can see why MOXy does it. If the JSON output needs to be unmarshalled back to a Java object, MOXy needs to know the type to create the correct object. However, in my case, the type is unsightly in the JSON output.

Jim
  • 49
  • 1
  • 3