9

私はSpring 3.1.2を使用しており、jsonオブジェクトをPOJOに解析する必要があります。これは、解析する必要がある json です。

{
"Person" : {
    "id" : "2"
 },
"Dog" : {
    "dateOfBirth" : "2012-08-20 00:00:00",
    "price" : "10.00"
    }
}

この json オブジェクト (2 つのオブジェクトを結合したもの) を 1 つの POJO に変換する必要があります。

public class MyClass{
     public MyClass(){}
     public MyClass(String personsId, TimeStamp dogsDateOfBirth, BigDecimal dogsPrice){
     .... // assign each parameter to the appropriate field
     }
     private String personsId;
     private TimeStamp dogsDateOfBirth;
     private BigDecimal dogsPrice;
     //... Getters and Setters for each field
}

さらに言えばObjectMapper mapper = new ObjectMapper(); 、いくつかのjsonオブジェクトがあるため、コードは次のようになります。

    String json = ... ;// A json with several objects as above
    JsonNode tree = mapper.readTree(json);
    Iterator<JsonNode> iter = tree.path("data").getElements();
    while (iter.hasNext()){
        JsonNode node = iter.next();
        MyClass myClass = mapper.readValue(node, MyClass.class);
        ... // do something with myClass object
    }

これを実行すると、次の例外が発生します。

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...MyClass]: can not instantiate from JSON object (need to add/enable type information?)

シンプルな POJO を作成しようとしました - Person:

public class Person{
        private String id;          
        public Person(){}
        public Person(String id){
            this.id = id;
         }
         ... // Getter and Setter
    }

次の操作を行います。

Person person = mapper.readValue(node.path("Person"), Person.class);

私はこの(同じ)例外を受け取ります:

org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...Person]: can not instantiate from JSON object (need to add/enable type information?)

型情報についていくつか読み込もうとしましたが、ここでどのように役立つか理解できませんでした。

このjsonをPOJOに変換するにはどうすればよいですか?

ありがとう。

4

6 に答える 6

6

私がしたことは次のとおりです。 Person オブジェクトと Dog オブジェクトを保持する新しいクラスを作成しました。これらのクラスは静的である必要があります (ここで見つけました)。クラスは次のとおりです。

public static class MyNewClass{
    private Person person;
    private Dog dog;
    ... // two constructors and getters and setters

 public static class Person{
     private String id;
     ... // two constructors and getters and setters
 }
 public static class Dog{
     private String dateOfBirth;
     private String price;
     ... // two constructors and getters and setters
  }
}

今私のコードは次のようになります:

    JsonNode tree = mapper.readTree(jsonString);
    Iterator<JsonNode> iter = tree.path("data").getElements();
    while (iter.hasNext()){
        JsonNode node = iter.next();
        Person person = mapper.readValue(node.path("Person"), Person.class);
        Dog dog = mapper.readValue(node.path("Dog"), Dog.class);
        MyNewClass myNewClass = new MyNewClass(person , dog);
        ... //Do something with it
    }

私はまだ、これら 2 つのオブジェクト ( Person と Dog ) を作成せずにやりたいと思っています。

ありがとう。

于 2012-08-27T12:25:09.367 に答える
4

問題はここで説明されているものと同じです: Jackson エラー: 適切なコンストラクターがありません

インスタンス化しようとしているクラスは静的ではありません。そのため、隠しコンストラクタ パラメータがあります。これにより、Jackson が失敗します。

于 2012-08-27T13:40:18.810 に答える
1

注: 私はEclipseLink JAXB (MOXy)のリーダーであり、JAXB (JSR-222)エキスパート グループのメンバーです。

MOXy のパス ベースのマッピングを活用して、ユース ケースをサポートできます。

私のクラス

@XmlPath注釈は、パス ベースのマッピングを指定するために使用されます。

package forum12139380;

import java.math.BigDecimal;
import java.sql.Timestamp;
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class MyClass {

    public MyClass() {
    }

    public MyClass(String personsId, Timestamp dogsDateOfBirth,
            BigDecimal dogsPrice) {
        this.personsId = personsId;
        this.dogsDateOfBirth = dogsDateOfBirth;
        this.dogsPrice = dogsPrice;
    }

    @XmlPath("Person/id/text()")
    private String personsId;

    @XmlPath("Dog/dateOfBirth/text()")
    private Timestamp dogsDateOfBirth;

    @XmlPath("Dog/price/text()")
    @XmlSchemaType(name="string")
    private BigDecimal dogsPrice;

    // ... Getters and Setters for each field

}

jaxb.properties

MOXy を JAXB プロバイダーとして指定するにjaxb.propertiesは、次のエントリを使用して、ドメイン モデルと同じパッケージに呼び出されるファイルを含める必要があります。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

デモ

以下のコードは、JSON をオブジェクトに変換してから JSON に戻します。

package forum12139380;

import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(2);
        properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
        properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {MyClass.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource json = new StreamSource("src/forum12139380/input.json");
        MyClass myClass = (MyClass) unmarshaller.unmarshal(json, MyClass.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(myClass, System.out);
    }

}

input.xml/出力

以下は、デモ コードの実行に対する入力と出力です。私の例では、MOXy のデフォルトの表現である を使用していますTimestamp。この表現は を使用して簡単に制御できますXmlAdapter(参照: jaxb unmarshal timestamp )。

{
   "Person" : {
      "id" : "2"
   },
   "Dog" : {
      "dateOfBirth" : "2012-08-20T00:00:00.0",
      "price" : "10.00"
   }
}
于 2012-08-27T13:25:02.163 に答える
1

Stringすべてのフィールドが JSON データの文字列であるため、すべてのフィールドを受け入れるように MyClass のコンストラクターを変更してみてください。ところで、JSON には TimeStamps の標準表現がないため、とにかく日付フィールドの変換を行う必要があります。「価格」フィールドについては、変更してみてください

"price" : "10.00"

"price" : 10.00

JSON データ内。これにより、BigDecimal として読み取れるようになります。

于 2012-08-27T09:38:00.103 に答える
1

2 つの json オブジェクトを 1 つの Java オブジェクトに結合する場合は、Genson ライブラリhttp://code.google.com/p/genson/を使用したソリューションがあります。次のコードは短縮して Gensons 標準コンバーターを使用できますが、例としてはあまり明確ではありません。ここでの利点は、ストリーミング API を直接使用しているため、非常に高速であることです。

class MyClassConverter implements Deserializer<MyClass> {
    @Override
    public MyClass deserialize(ObjectReader reader, Context ctx)
            throws TransformationException, IOException {
        reader.beginObject();
        MyClass myClass = new MyClass();
        for (; reader.hasNext();) {
            reader.next();
            if ("Person".equals(reader.name())) {
                readPerson(reader, myClass);
            } else if ("Dog".equals(reader.name())) {
                readDog(reader, myClass);
            }
        }
        reader.endObject();
        return myClass;
    }

    private void readPerson(ObjectReader reader, MyClass myClass) throws IOException {
        reader.beginObject();
        for (; reader.hasNext();) {
            reader.next();
            if ("id".equals(reader.name()))
                myClass.setPersonsId(reader.valueAsString());
        }
        reader.endObject();
    }

    private void readDog(ObjectReader reader, MyClass myClass) throws IOException {
        reader.beginObject();
        for (; reader.hasNext();) {
            reader.next();
            if ("dateOfBirth".equals(reader.name()))
                myClass.setDogsDateOfBirth(Timestamp.valueOf(reader.valueAsString()));
            else if ("price".equals(reader.name()))
                myClass.setDogsPrice(new BigDecimal(reader.valueAsString()));
        }
        reader.endObject();
    }
}

Person と Dog を別々のオブジェクトとして使用する他の例が必要な場合は、Gensons ユーザー グループで質問できます。

お役に立てれば!

編集 これは、より短くて優れた別のバージョンですが、リリースされたバージョン0.91には含まれていません(私が作成者であるため、おそらく今日新しいバージョンをリリースします:))それを機能させるには、ゲッターに注釈を付ける必要があります(およびセッターも@JsonProperty(the_name_from_json) を使用してシリアル化を行います。Genson は、必要に応じてフィールドのみを使用できる場合はゲッター/セッターを必要としないことに注意してください (デフォルトでは、利用可能な場合はゲッター/セッターを使用します。それ以外の場合はフィールドを使用します)。

Genson genson = new Genson.Builder().withDeserializerFactory(new MyClassConverterFactory()).create();
MyClass myClass = genson.deserialize(json, MyClass.class);

public static class MyClassConverterFactory implements Factory<Deserializer<MyClass>> {
    @SuppressWarnings("unchecked")
    @Override
    public Deserializer<MyClass> create(Type type, Genson genson) {
        BeanDescriptor<MyClass> myClassDescriptor = (BeanDescriptor<MyClass>) genson.getBeanDescriptorFactory().provide(MyClass.class, genson);
        return new MyClassConverter(myClassDescriptor);
    }
}

public static class MyClassConverter implements Deserializer<MyClass> {
    BeanDescriptor<MyClass> myClassDescriptor;
    public MyClassConverter(BeanDescriptor<MyClass> myClassDescriptor) {
        this.myClassDescriptor = myClassDescriptor;
    }

    @Override
    public MyClass deserialize(ObjectReader reader, Context ctx)
            throws TransformationException, IOException {
        reader.beginObject();
        MyClass myClass = new MyClass();
        for (; reader.hasNext();) {
            reader.next();
            if ("Person".equals(reader.name())) {
                myClassDescriptor.deserialize(myClass, reader, ctx);
            } else if ("Dog".equals(reader.name())) {
                myClassDescriptor.deserialize(myClass, reader, ctx);
            }
        }
        reader.endObject();
        return myClass;
    }
}
于 2012-08-27T12:01:03.600 に答える