json-iterator / java

jsoniter (json-iterator) is fast and flexible JSON parser available in Java and Go
http://jsoniter.com/
MIT License
1.51k stars 519 forks source link

Codegen fails to generate Enum decoder if Enum has overriden toString() method #320

Open alku0571 opened 2 years ago

alku0571 commented 2 years ago

If Enum has override on toString() method then codegen fails.

Example:

Given model:

public enum AnimalType {

    ELEPHANT("elephant");

    private String typeName;

    private AnimalType(String typeName) {
        this.typeName = typeName;
    }

    @Override
    public String toString() {
        return typeName;
    }
}
public class Animal {

    private String name;
    private AnimalType type;

    //setters, getters omitted
}

Test:

@Test
public void testJsoniterExampleDeserialize() {
    //DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH fails too
    JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_STRICTLY); 

    //Please notice that JSON don't even have AnimalType specified.
    Animal animal = JsonIterator.deserialize("{'name': 'johny'}".replace('\'', '"'), Animal.class);
}

Gives exception:

com.jsoniter.spi.JsonException: failed to generate decoder for: com.jsoniter.spi.ClassInfo@582ac61f with [], exception: javassist.CannotCompileException: [source error] no such field: AnimalType$elephant
public static java.lang.Object decode_(com.jsoniter.JsonIterator iter) throws java.io.IOException { if (iter.readNull()) { return null; }
com.jsoniter.spi.Slice field = com.jsoniter.CodegenAccess.readSlice(iter);
switch (field.len()) {
case 8: 
if (
field.at(0)==101 && 
field.at(1)==108 && 
field.at(2)==101 && 
field.at(3)==112 && 
field.at(4)==104 && 
field.at(5)==97 && 
field.at(6)==110 && 
field.at(7)==116
) {
return AnimalType.elephant;
}
break;

}
throw iter.reportError("decode enum", field + " is not valid enum for AnimalType");
}

    at com.jsoniter.Codegen.gen(Codegen.java:86)
    at com.jsoniter.Codegen.getDecoder(Codegen.java:25)
    at com.jsoniter.CodegenImplNative.genReadOp(CodegenImplNative.java:213)
    at com.jsoniter.CodegenImplNative.genField(CodegenImplNative.java:191)
    at com.jsoniter.CodegenImplObjectStrict.addFieldDispatch(CodegenImplObjectStrict.java:331)
    at com.jsoniter.CodegenImplObjectStrict.addFieldDispatch(CodegenImplObjectStrict.java:344)
    at com.jsoniter.CodegenImplObjectStrict.addFieldDispatch(CodegenImplObjectStrict.java:344)
    at com.jsoniter.CodegenImplObjectStrict.addFieldDispatch(CodegenImplObjectStrict.java:344)
    at com.jsoniter.CodegenImplObjectStrict.renderTriTree(CodegenImplObjectStrict.java:304)
    at com.jsoniter.CodegenImplObjectStrict.genObjectUsingStrict(CodegenImplObjectStrict.java:93)
    at com.jsoniter.Codegen.genSource(Codegen.java:241)
    at com.jsoniter.Codegen.gen(Codegen.java:68)
    at com.jsoniter.Codegen.getDecoder(Codegen.java:25)
    at com.jsoniter.JsonIterator.read(JsonIterator.java:385)
    at com.jsoniter.JsonIterator.read(JsonIterator.java:375)
    at com.jsoniter.JsonIterator.deserialize(JsonIterator.java:441)
    at com.jsoniter.JsonIterator.deserialize(JsonIterator.java:411)

To fix this issue it's enough to slightly modify com.jsoniter.CodegenImplEnum:38

change byte[] fromNameBytes = e.toString().getBytes();

to

byte[] fromNameBytes = ((Enum)e).name().getBytes();