简体   繁体   中英

JSON to object issue with Jersey and Genson

I'm running into the following problem when trying to execute a POST call using Jersey and Genson:

.... com.owlike.genson.JsonBindingException: No constructor has been found for type interface Animal ....

I have the following setup:

-> Animal.java

package com.test;

import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes( {@JsonSubTypes.Type(value = Dog.class, name = "dog") })
public interface Animal
{  }

-> Dog.java

package com.test;

import org.codehaus.jackson.annotate.JsonTypeName;
import org.codehaus.jackson.annotate.JsonProperty;

@JsonTypeName("dog")
public class Dog implements Animal
{
   @JsonProperty
   public String name;

   public String getName() { return name; }
   public void setName(String n) { this.name = n; }
}

-> Zoo.java

package com.test;

import java.util.List;

public class Zoo
{
   private List<Animal> animals;
   public List<Animal> getAnimals()
   {
     return animals;
   }

   public void setAnimals(List<Animal> animals)
   {
    this.animals = animals;
    } 
 }

-> GensonCustomResolver.java

package com.test;
import javax.ws.rs.next.ContextResolver;
import javax.ws.rs.next.Provider;

import com.owlike.genson.Genson;

@Provider
public class GensonCustomResolver implements ContextResolver<Genson>
{
   private final Genson genson = new      Genson.Builder().useRuntimeType(true).useClassMetadata(true).create();

   @Override
   public Genson getContext(Class<?> arg0)
   {
     return genson;
   }
}

-> JerseyService.java

package com.test;

import javax.ws.rs.*;
import org.codehaus.jackson.*;

@Path("/exampleservice")
public class JerseyService 
{


   @POST
   @Path("somePath")
   @Consumer(MediaType.APPLICATION_JSON)
   @Produces(MediaType.APPLICATION_JSON)
   public Zoo createAnotherZoo(Zoo zoo) throws JsonParseException, JsonMappingException, Exception
   {
      Zoo newZoo = new Zoo();
      Collection<Animal> animals = zoo.getAnimals();
      List<Animal> newAnimals = new ArrayList<Animal>();

      for (Animal a : animals) {
          Dog dog_a = (Dog) a;
          Dog dog_b = new Dog();
          dog_b.setName(dog_a.getName() + "TEST");
          newAnimals.add(dog_b);
      }
      newZoo.add(newAnimals);
      return newZoo;
   }
}

The input JSON looks like this:

{
   "animals" : [
     {
       "name": "Unno"
     }
    ]
}

To summarize, I have a List and I'm trying to use one of the interface implementations when deserializing my objects.

Thank you in advance.

::::SOLUTION:::::

In case anyone runs into this:

I removed genson dependencies completely as suggested below. Only used jackson annotations and it seemed to work. Also I removed the @JsonProperty from the name attribute in the Dog.java.

Thank you :) :)

I think you mean "I'm trying to use one of the interface implementations when deserializing my objects."

Your problem

If it is what you mean, then the short answer is it can not work like that.

  1. I see you are using Jackson annotations, Genson does not see/use those annotations (jackson and genson a two different libraries).

  2. Based on the json stream (the sample input you provided) Genson has no way of knowing to which concrete class to bind .


Some possible solutions would be

  • If you use the same pojos (animal, dog, etc) and Genson on both ends (the code that will post the data to the server and the server), then using a Genson instance with useRuntimeType and useClassMetadata enabled on both ends should work. It would be the easiest solution.

    • The class metadata mechanism, during serialization writes in the json object as first entry the class name of the concrete type, during deserialization Genson looks for this first attribute with key @class to extract the concrete class name. In your case if you are able to produce a json of the form {"animals":{"@class": "com.test.Dog", "name": "Unno"}}, then genson would deser it to the correct type. Note that you can also register aliases for types, so you could just write dog instead of the full class name. More details in the documentation .

    • As you have those Jackson annotations to give type hints, then you could also use jackson to handle the deser (note that the input json would not work with this configuration as it does not seem to contain the informations defined via the annotations). In this case you should not use Genson to handle the ser/de with jersey as jackson and genson do both the same job.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM