19

Jackson?

この組み合わせを使用する場合、Jackson でそれが可能であることはわかっています。1) Java 8、2) 「-parameters」オプションを使用してコンパイル、3) パラメータ名が JSON に一致します。しかし、これらすべての制限なしでデフォルトで GSON でも可能です。

例えば:

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public static void main(String[] args) throws IOException {
        String json = "{firstName: \"Foo\", lastName: \"Bar\", age: 30}";
        
        System.out.println("GSON: " + deserializeGson(json)); // works fine
        System.out.println("Jackson: " + deserializeJackson(json)); // error
    }

    public static Person deserializeJackson(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        return mapper.readValue(json, Person.class);
    }

    public static Person deserializeGson(String json) {
        Gson gson = new GsonBuilder().create();
        return gson.fromJson(json, Person.class);
    }
}

これは GSON では問題なく動作しますが、Jackson は次のようにスローします。

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `jacksonParametersTest.Person` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{firstName: "Foo", lastName: "Bar", age: 30}"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)

GSON では可能であるため、Person クラスを変更せずに、Java 8 を使用せず、明示的なカスタム デシリアライザーを使用せずに、Jackson に何らかの方法があるはずです。誰かが解決策を知っていますか?

  • 更新、追加情報

Gson は引数コンストラクターをスキップしているように見えるため、リフレクションを使用して舞台裏で引数なしのコンストラクターを作成しているに違いありません。

また、 「-parameters」コンパイラ フラグがなくても、Kotlin データ クラスに対してこれを実行できるKotlin Jackson モジュールが存在します。したがって、Java Jackson にそのようなソリューションが存在しないように見えるのは奇妙です。

これは、Kotlin Jackson で利用できる (素晴らしくクリーンな) ソリューションです (この IMO は、カスタム モジュールを介して Java Jackson でも利用できるようになるはずです)。

val mapper = ObjectMapper()
    .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
    .registerModule(KotlinModule())     
        
val person: Person = mapper.readValue(json, Person::class.java)
4

4 に答える 4

1

デフォルトのコンストラクターがないため、jackson または gson は独自にインスタンスを作成したいと考えています。カスタム逆シリアル化を提供して、そのようなインスタンスを作成する方法を API に伝える必要があります。

ここにスニペットコード

public class PersonDeserializer extends StdDeserializer<Person> { 
    public PersonDeserializer() {
        super(Person.class);
    } 

    @Override
    public Person deserialize(JsonParser jp, DeserializationContext ctxt) 
            throws IOException, JsonProcessingException {
        try {
            final JsonNode node = jp.getCodec().readTree(jp);
            final ObjectMapper mapper = new ObjectMapper();
            final Person person = (Person) mapper.readValue(node.toString(),
                    Person.class);
            return person;
        } catch (final Exception e) {
            throw new IOException(e);
        }
    }
}

次に、タイプを処理するように単純なモジュールを登録します

final ObjectMapper mapper = jacksonBuilder().build();
SimpleModule module = new SimpleModule();
module.addDeserializer(Person.class, new PersonDeserializer());
于 2017-11-30T13:42:35.143 に答える