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に変換するにはどうすればよいですか?
ありがとう。
私がしたことはこれでした: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)を作成せずにそれをやりたいです-それは今のところ十分です-しかし誰かがアイデアを持っているなら-私はここに行きたいです!
ありがとう。
問題はここで説明したものと同じです: ジャクソンエラー:適切なコンストラクターがありません
インスタンス化しようとしているクラスは静的ではありません。そのため、コンストラクターパラメーターが非表示になっています。これがジャクソンの失敗の原因です。
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ユーザーグループで質問できます。
お役に立てれば!
[〜#〜] edit [〜#〜]これは、より短くてより良い別のバージョンですが、リリースされたバージョン0.91には含まれていません(おそらくリリースします私が作者である今日の新しいバージョン:))それを機能させるには、@ JsonProperty(the_name_from_json)でゲッター(およびシリアル化も行う場合はセッター)に注釈を付ける必要があります。 Gensonは、フィールドのみを使用できるようにする場合は、getter/setterを必要としないことに注意してください(デフォルトでは、フィールドが使用可能な場合はgetter/setterを使用します)。
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;
}
}
注:私は EclipseLink JAXB(MOXy) リードおよび JAXB(JSR-222) エキスパートグループのメンバー。
MOXyのパスベースのマッピングを活用して、ユースケースをサポートできます。
MyClass
@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/Output
以下は、デモコードの実行への入力と実行からの出力です。私の例では、MOXyのデフォルトの表現であるTimestamp
を使用しています。この表現は、XmlAdapter
を使用して簡単に制御できます(参照: jaxb unmarshalタイムスタンプ )。
{
"Person" : {
"id" : "2"
},
"Dog" : {
"dateOfBirth" : "2012-08-20T00:00:00.0",
"price" : "10.00"
}
}
これらすべての回答は、POJOを使用することがそれを行う唯一の方法であることを意味します。明らかに、Spring WebサービスプロジェクトのようなWebプロジェクトでは、POJOを使用することが重要ですが、単体テストのためだけに、汎用のJackson JsonNodeオブジェクトを使用することはできませんか?
POJOクラスを使用せずに、Jackson ObjectMapperを使用してJsonNodeに単純に逆シリアル化することはできませんか? JsonNodeのインスタンスは、それ自体が合法的なJackson POJOとして適格ではありませんか? JsonNodeインスタンスを取得すると、次のようにjson内のオブジェクトを取得できるためです。
node.get(0).get(1).get("nodename").asText();
すべてのフィールドはJSONデータの文字列であるため、MyClassのコンストラクターを変更して、すべてのフィールドでString
を受け入れるようにしてください。ところで、JSONにはTimeStampsの標準表現がないため、とにかく日付フィールドの変換を行う必要があります。 「価格」フィールドについては、変更してみてください
"price" : "10.00"
に
"price" : 10.00
jSONデータ内。これにより、BigDecimalとして読み取ることができます。