Danilo M.
Danilo M.

Reputation: 1592

Cannot construct instance of - Jackson

I am using Jackson and I'm having problems, when I try to deserialize an Object I get the following error:

com.fasterxml.jackson.databind.JsonMappingException: 
    Can not construct instance of net.MyAbstractClass, 
    problem: abstract types either need to be mapped to concrete types, 
        have custom deserializer, or be instantiated with additional type information

I am having problems in the attribute:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "@id")
@JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })
@ManyToOne
private MyAbstractClass object;

Could anyone help me?

Upvotes: 122

Views: 383770

Answers (11)

jumping_monkey
jumping_monkey

Reputation: 7865

Issue

I had this interface, used by Spring Data JPA, for projection:

public interface xxxProjection {

and Jackson, rightly so, did not know how to deserialize/construct the object.

Solution

@JsonDeserialize(as = xxxProjectionImpl.class)
public interface xxxProjection {

    String getkey();
    String getValue();
}

@Getter
class xxxProjectionImpl implements xxxProjection {
    private String key;
    private String value;
}

Upvotes: 0

sudha mosalikanti
sudha mosalikanti

Reputation: 171

Setting a default constructor helped to resolve

Upvotes: 1

Jean-Claude MBENG
Jean-Claude MBENG

Reputation: 11

Using lombok I had the same issue, I have tried this to solve

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder

Upvotes: 0

Gabriel Andrade
Gabriel Andrade

Reputation: 728

I was having this issue using lombok's @Data and @Builder annotations alone, which I replaced with:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder

And it solved my problem.

Upvotes: 35

Nuñito Calzada
Nuñito Calzada

Reputation: 1648

Use @JsonDeserialize(contentAs= ConcreteCLass.class)

Upvotes: 2

Roheet Kamble
Roheet Kamble

Reputation: 1

Use lombok annotation.

@AllArgsConstructor
@NoArgsConstructor
@Builder
@JsonPropertyOrder({"name", "id"})
public class CreationUser {
    @Builder.Default
    @JsonProperty("name")
    String name = "";

    @Builder.Default
    @JsonProperty("id")
    String id = "";
}

Upvotes: 0

ACV
ACV

Reputation: 10560

In your concrete example the problem is that you don't use this construct correctly:

@JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })

@JsonSubTypes.Type should contain the actual non-abstract subtypes of your abstract class.

Therefore if you have:

abstract class Parent and the concrete subclasses

Ch1 extends Parent and Ch2 extends Parent

Then your annotation should look like:

@JsonSubTypes({ 
          @JsonSubTypes.Type(value = Ch1.class, name = "ch1"),
          @JsonSubTypes.Type(value = Ch2.class, name = "ch2")
})

Here name should match the value of your 'discriminator':

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, 
include = JsonTypeInfo.As.WRAPPER_OBJECT, 
property = "type")

in the property field, here it is equal to type. So type will be the key and the value you set in name will be the value.

Therefore, when the json string comes if it has this form:

{
 "type": "ch1",
 "other":"fields"
}

Jackson will automatically convert this to a Ch1 class.

If you send this:

{
 "type": "ch2",
 "other":"fields"
}

You would get a Ch2 instance.

Upvotes: 5

Asif
Asif

Reputation: 535

You need to use a concrete class and not an Abstract class while deserializing. if the Abstract class has several implementations then, in that case, you can use it as below-

  @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({ 
      @Type(value = Bike.class, name = "bike"), 
      @Type(value = Auto.class, name = "auto"), 
      @Type(value = Car.class, name = "car")
    })
    public abstract class Vehicle {
        // fields, constructors, getters, setters
    }

Upvotes: 24

ZIA UR REHMAN
ZIA UR REHMAN

Reputation: 179

For me there was no default constructor defined for the POJOs I was trying to use. creating default constructor fixed it.

public class TeamCode {

    @Expose
    private String value;

    public String getValue() {
        return value;
    }

    **public TeamCode() {
    }**

    public TeamCode(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "TeamCode{" +
                "value='" + value + '\'' +
                '}';
    }

    public void setValue(String value) {
        this.value = value;
    }

}

Upvotes: 5

jlabedo
jlabedo

Reputation: 1166

You cannot instantiate an abstract class, Jackson neither. You should give Jackson information on how to instantiate MyAbstractClass with a concrete type.

See this answer on stackoverflow: Jackson JSON library: how to instantiate a class that contains abstract fields

And maybe also see Jackson Polymorphic Deserialization

Upvotes: 77

StaxMan
StaxMan

Reputation: 116620

Your @JsonSubTypes declaration does not make sense: it needs to list implementation (sub-) classes, NOT the class itself (which would be pointless). So you need to modify that entry to list sub-class(es) there are; or use some other mechanism to register sub-classes (SimpleModule has something like addAbstractTypeMapping).

Upvotes: 6

Related Questions