動的にJSONからのオブジェクトを作成するクラスを選択します

B15:

私はトラブルのためにきれいな解決策を考え出すを抱えていることは興味深い問題があります。私のアプリケーションは、それがこのまたはJSON自体のフィールドに基づいて、そのクラス型にデシリアライズする必要があることをJSONオブジェクトのコレクションを読み込みます。私は、JSONの構造やそれがどのように自分のアプリケーションに取得を制御することはできません。

私は、アプリケーションに来ることができ、オブジェクトの種類ごとにモデルを作成しましたし、私はその後、「タイプ」フィールド引き出し、がにJSONをデシリアライズするObjectMapperを使用するサービスを構築しようとしている点に達しました適切なモデル。

JSONの例:

{
    "message_type" : "model1"
    "other data" : "other value"
    ...
}

モデル:

public class Model1 {
    ...
}

public class Model2 {
    ...
}

サービス?:

public class DynamicMappingService {

    public ???? mapJsonToObject(String json) {
        String type = pullTypeFromJson();

        ???
    }

    private String pullTypeFromJson() {...}
}

私は、私はそれをしてきれいな何かを考え出すのに苦労している「タイプの値は、これはその後、ということにデシリアライズされた場合」という巨大なswitch文を望んでいません。私は多分、一般的なパラメータは、モデルタイプと専用フィールドは、そのモデルタイプのインスタンスであるが、それは右のいずれかいないようで、一般的なモデルクラスを考えて、私はどのようなもの買い、私はよく分かりません。モデルのすべてが延びていること、私はまた、空の抽象クラスのいくつかの並べ替えを持っている可能性がありますが、それはあまりにも恐ろしいようです。どのように私はこれに対処するのですか?たとえば余分なポイント。

Conffusion:

私は2クラスの車やトラックを持つ親インターフェイス車の概念を使用しています。あなたにはMODEL1とモデル2は、共通のインタフェースを実装する必要があり、この手段をケース。

私のテストクラス:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Tester {
    static ObjectMapper mapper=new ObjectMapper();

    public static void main(String[] args) throws IOException {
        Car car = new Car();
        car.setModel("sedan");
        String jsonCar=mapper.writeValueAsString(car);
        System.out.println(jsonCar);
        Vehicle c=mapper.readValue(jsonCar, Vehicle.class);
        System.out.println("Vehicle of type: "+c.getClass().getName());

        Truck truck=new Truck();
        truck.setPower(100);
        String jsonTruck=mapper.writeValueAsString(truck);
        System.out.println(jsonTruck);
        Vehicle t=mapper.readValue(jsonTruck, Vehicle.class);
        System.out.println("Vehicle of type: "+t.getClass().getName());
    }
}

どこかは、あなたがタイプフィールドの値と対応するクラス間のマッピングを格納する必要があります。あなたがこれをする場所に応じて、実装が異なっています。

1)親の型は、サブタイプのリストを保持します。

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonSubTypes({
    @JsonSubTypes.Type(value = Car.class, name = "car"),
    @JsonSubTypes.Type(value = Truck.class, name = "truck") }
)
@JsonTypeInfo(
          use = JsonTypeInfo.Id.NAME, 
          include = JsonTypeInfo.As.PROPERTY, 
          property = "type")
public interface Vehicle {
}

車とトラックのためのモデルは、任意の注釈のない単純なPOJOです。

public class Car implements Vehicle {
    private String model;

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }
}

2)別のレゾルバは、マッピングを保持しています。

車両は、余分な注釈が含まれています@JsonTypeIdResolver

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;

@JsonTypeInfo(
          use = JsonTypeInfo.Id.NAME, 
          include = JsonTypeInfo.As.PROPERTY, 
          property = "type")
@JsonTypeIdResolver(JsonResolver.class)
public interface Vehicle {
}

JsonResolverクラスは、タイプフィールドの値とクラスの間のマッピングを保持しています:

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;

public class JsonResolver extends TypeIdResolverBase {

    private static Map<String,Class<?>> ID_TO_TYPE=new HashMap<>();
    static {
        ID_TO_TYPE.put("car",Car.class);
        ID_TO_TYPE.put("truck",Truck.class);
    }
    public JsonResolver() {
        super();
    }

    @Override
    public Id getMechanism() {
        return null;
    }

    @Override
    public String idFromValue(Object value) {
        return value.getClass().getSimpleName();
    }

    @Override
    public String idFromValueAndType(Object value, Class<?> arg1) {
        return idFromValue(value);
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id) {
        return context.getTypeFactory().constructType(ID_TO_TYPE.get(id));
    }
}

3)JSONは完全なクラス名が含まれています。

あなたはシリアル化されたJSONは、完全なJavaクラス名を保持して受け入れる場合は、リゾルバが、指定する必要はありませんuse = JsonTypeInfo.Id.CLASS

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;

@JsonTypeInfo(
          use = JsonTypeInfo.Id.CLASS, 
          include = JsonTypeInfo.As.PROPERTY, 
          property = "type")
public interface Vehicle {
}

解決策3は実装が最も簡単ですが、個人的に私は私のデータでは、完全なJavaクラス名を持っているという考えが好きではありません。あなたはJavaパッケージをリファクタリングし始める場合、それは潜在的なリスクとなる可能性があります。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=230826&siteId=1