Mayurb
Mayurb

Reputation: 577

JsonMappingException: Can not deserialize instance of enum out of START_OBJECT token

My Json looks like following

{
name: "math",
code:null,
description:"Mathematics",
id:null,
name:"math",
noExam:null,
teacher:{
	id: "57869ced78aa7da0d2ed2d92", 
	courseGroup:"LKG",
	experties:[{type: "SOCIALSTUDIES", id: "3"}, {type: "PHYSICS", id: "4"}]

	},
id:"57869ced78aa7da0d2ed2d92"
}

if you see my entity classes, I have a set of enums in Teacher.java

When I try to post this I get error

JsonMappingException: Can not deserialize instance of com.iris.fruits.domain.enumeration.Experties out of START_OBJECT token

I have tried almost all solutions out there, like DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, but without success.

public class Subject implements Serializable {
// all the other fields 
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;
  
  // getter and setter
  }



public class Teacher implements Serializable {
// all the other fields 
  
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String id;

    @Enumerated(EnumType.STRING)
    @Column(name = "experties")
    @JsonProperty("experties")
    private List< Experties> experties;

  // getter and setter
  }


 
 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Experties implements Serializable {
    MATH(1,"MATH"),
    SCIENCE(2,"SCIENCE"),
    SOCIALSTUDIES(3,"SOCIALSTUDIES"),
    PHYSICS(4,"PHYSICS"), 
    CHEMISTRY(5,"CHEMISTRY");
	
	@JsonSerialize(using = ToStringSerializer.class) 
	private String type;
	
	@JsonSerialize(using = ToStringSerializer.class) 
	private Integer id;
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	
	Experties(Integer id, final String type) {
		this.id = id;		
		this.type = type; 
	}
	
	
}

Upvotes: 5

Views: 9825

Answers (4)

Lubo
Lubo

Reputation: 1847

You have this issue because you have a custom serializer in your enum @JsonFormat(shape = JsonFormat.Shape.OBJECT). Jackson does not know how to deserialize object from json, into enum. You can create "creator" method to solve this easily:

public enum Experties implements Serializable {
    @JsonCreator
    public Experties(String type) {
        // here you can use "type" attribute from json object to create your Enum instance. If you need, you can also add as parameter "Integer Id", as it is in your enum json representation.
        return valueOf(type);
    }
}

Upvotes: 0

Julien Kronegg
Julien Kronegg

Reputation: 5251

You have this issue because you have a custom serializer in your enum (@JsonFormat(shape = JsonFormat.Shape.OBJECT)). Thus, to solve the issue, you need a custom deserializer.

You can define a custom deserializer using :

@JsonFormat(shape = JsonFormat.Shape.OBJECT) // custom serializer
@JsonDeserialize(using = MyEnumDeserializer.class) // custom deserializer
public enum Experties implements Serializable {
    ...
}

The custom deserializer being :

public static class MyEnumDeserializer extends JsonDeserializer<Experties> {
    @Override
    public Experties deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        String type = node.get("type").asText();
        return Stream.of(Experties.values())
           .filter(enumValue -> enumValue.getType().equals(type))
           .findFirst()
           .orElseThrow(() -> new IllegalArgumentException("type "+type+" is not recognized"));
    }
}

Of course, you can have another deserializer implementation (e.g. use the id field instead of the type field, check the coherence between the id and type fields).

Upvotes: 4

eslXst
eslXst

Reputation: 131

Add JsonDeserialize annotation to experties setter in Teacher class:

@JsonDeserialize(using = EnumDeserializer.class)
public void setExperties(List experties){
//...
}

Upvotes: 0

rsh
rsh

Reputation: 79

Your class should match with the structure of the json. And in your input json shouldn't repeat keys.

I guess you classes, should like below:

public class Subject implements Serializable {
// all the other fields 
    String name;
    String code;
    String description;
    String id;
    String noExam;
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;

  // getter and setter
  }



public class Teacher implements Serializable {
// all the other fields 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String id;

    @Enumerated(EnumType.STRING)
    @Column(name = "experties")
    @JsonProperty("experties")
    private List< Experties> experties;

    String courseGroup;
  // getter and setter
  }



 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Experties implements Serializable {
    MATH(1,"MATH"),
    SCIENCE(2,"SCIENCE"),
    SOCIALSTUDIES(3,"SOCIALSTUDIES"),
    PHYSICS(4,"PHYSICS"), 
    CHEMISTRY(5,"CHEMISTRY");

    @JsonSerialize(using = ToStringSerializer.class) 
    private String type;

    @JsonSerialize(using = ToStringSerializer.class) 
    private Integer id;

    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }


    Experties(Integer id, final String type) {
        this.id = id;       
        this.type = type; 
    }


}

Upvotes: 0

Related Questions