2017-01-27 6 views
1

私はgsonが新しく、オブジェクト内のリストを逆シリアル化する方法を試しています。gson - リストを含むオブジェクトをデシリアライズする

エラーメッセージは、私が行ったPlayer用のInstanceCreatorの作成を示唆しています。 しかし実装されたとき、デシリアライズされたオブジェクトには、json文字列から値を取得するのではなく、nameフィールドが 'default value'に設定されたPlayerのリストが含まれていました。だから私は今、そのアプローチが正しいかどうか疑問に思っています。

これは私が2人の選手

Team t = new TeamImpl("teamname"); 
t.addPlayer(new PlayerImpl("p1")); 
t.addPlayer(new PlayerImpl("p2")); 
Gson gson = new Gson(); 
String json = gson.toJson(t);  

で新しいチームを作成するための簡単なテストを持っている私が働いているモデルの単純化であるが、問題を浮き彫りに...

public interface Player { 
    String name(); 
} 

public class PlayerImpl implements Player { 

    private String name; 

    public PlayerImpl(String name) { 
     this.name = name; 
    } 

    public String name() { return this.name; } 
} 

public interface Team { 
... 
} 

public class TeamImpl implements Team { 

    String name; 
    List<Player> players = new ArrayList<>(); 

    public TeamImpl(String teamName) { this.name = teamName; } 

    ... 
} 

次のjson文字列を作成します。

{"name":"teamname","players":[{"name":"p1"},{"name":"p2"}]} 

ただし、json文字列を逆シリアル化すると、

Team t2 = gson.fromJson(json, TeamImpl.class); 

私は次のエラーを取得する:

java.lang.RuntimeException: Unable to invoke no-args constructor for interface com.example.Player. Register an InstanceCreator with Gson for this type may fix this problem. 

    at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:226) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) 
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220) 
    at com.google.gson.Gson.fromJson(Gson.java:887) 
    at com.google.gson.Gson.fromJson(Gson.java:852) 
    at com.google.gson.Gson.fromJson(Gson.java:801) 
    at com.google.gson.Gson.fromJson(Gson.java:773) 
    at com.example.data.JsonDataTests.test_team_json(JsonDataTests.java:62) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99) 
    at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81) 
    at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) 
    at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75) 
    at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45) 
    at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:71) 
    at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35) 
    at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42) 
    at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) 
    at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:121) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) 
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 
Caused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: com.example.Player 
    at com.google.gson.internal.UnsafeAllocator.assertInstantiable(UnsafeAllocator.java:117) 
    at com.google.gson.internal.UnsafeAllocator.access$000(UnsafeAllocator.java:31) 
    at com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:49) 
    at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223) 
    ... 35 more 
+0

てみリストプレーヤー=新しいのArrayListを<>()回答されています。リストの代わりに players = new ArrayList <>();エラーが発生したため、TeamImplでインタフェースをインスタンス化できません!インターフェイス名:com.example.Player – Milaci

答えて

0

Gsonは、直列化復元時にPOJOとないインタフェースで動作します。インターフェイスPlayerではなく、実装PlayerImplを使用してください。あなたが持っている種類の要件をサポートする他のライブラリ、Gensonがあります。

0

このエラーはCaused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: com.example.Player です。したがって、TeamImplのようなリストをこのリストのようにする必要があります。List Players = new ArrayList(); GSONではインタフェースをインスタンス化できないためです。

public interface Player { 
String name(); 
} 
public class PlayerImpl implements Player { 

private String name; 

public PlayerImpl(String name) { 
    this.name = name; 
} 

public String name() { return this.name; } 
} 


public interface Team { 

    void addPlayer(PlayerImpl p1); 
} 


import java.util.ArrayList; 
import java.util.List; 

public class TeamImpl implements Team { 

String name; 
List<PlayerImpl> players = new ArrayList<PlayerImpl>(); 

public TeamImpl(String teamName) { this.name = teamName; } 


@Override 
public void addPlayer(PlayerImpl p1) { 
    this.players.add(p1); 
} 
} 

And the main to test it: 
public static void main(String[] args) { 

Team t = new TeamImpl("teamname"); 
t.addPlayer(new PlayerImpl("p1")); 
t.addPlayer(new PlayerImpl("p2")); 
Gson gson = new Gson(); 
String json = gson.toJson(t); 

System.out.println(json); 

Team t2 = gson.fromJson(json, TeamImpl.class); 
System.out.println(t2.toString()); 

} 

`

2

Gsonは明らかにそれはインターフェイスをインスタンス化できないことを報告します。インスタンスを直列化してデシリアライズする方法を知っているカスタム型のアダプタを登録することができます。

final class InterfaceSerializer<T> 
     implements JsonSerializer<T>, JsonDeserializer<T> { 

    private final Class<T> implementationClass; 

    private InterfaceSerializer(final Class<T> implementationClass) { 
     this.implementationClass = implementationClass; 
    } 

    static <T> InterfaceSerializer<T> interfaceSerializer(final Class<T> implementationClass) { 
     return new InterfaceSerializer<>(implementationClass); 
    } 

    @Override 
    public JsonElement serialize(final T value, final Type type, final JsonSerializationContext context) { 
     final Type targetType = value != null 
       ? value.getClass() // `type` can be an interface so Gson would not even try to traverse the fields, just pick the implementation class 
       : type;   // if not, then delegate further 
     return context.serialize(value, targetType); 
    } 

    @Override 
    public T deserialize(final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) { 
     return context.deserialize(jsonElement, implementationClass); 
    } 

} 

そして(一度アプリケーションごとに、Gsonは不変で、スレッドセーフです)あなたのGsonインスタンスを設定:今でもTeam t2 = gson.fromJson(json, Team.class);が働くだろう

Gson gson = new GsonBuilder() 
     .registerTypeAdapter(Player.class, interfaceSerializer(PlayerImpl.class)) 
     .registerTypeAdapter(Team.class, interfaceSerializer(TeamImpl.class)) 
     .create(); 

注記(無TeamImpl.class

たぶん。私は、Gsonのインターフェイスにバインドしないことを強くお勧めします。Gsonの唯一の責任は、ビジネス/値オブジェクトからのシリアル化とデシリアライズですアプリケーションはで動作します。問題を記述するData Transfer Objectパターンを見て、データをアプリケーションとの間で転送するオブジェクトの分割を提案してください。これにより、DTOからインターフェイスを削除することができます。そのようなアダプタは不要であり、DTOクラスがどのように宣言され、注釈付けされているかは気にしません。 TeamDtoPlayerDtoがあり、インターフェイスを実装することすらできないかもしれないが、データを明確にバインドしていることが分かっている場合は、class TeamDto { private List<PlayerDto> }と言ってください。DTOは簡単な実装に簡単に変換でき、同様に容易に構築できます。そのクラス#のnewInstanceを呼び出し、ここ

Team t2 = gson.fromJson(json, TeamImpl.class); 

問題は、あなたにはデフォルトコンストラクタ(引数なし)を持っていないということです。

0

他の回答はほとんど正しいですが、あなたはfromJson方法に代わりインターフェースのクラスを提供しているという事実を逃しました不可能である。あなたがGSONにカスタムデシリアライザを提供する必要が

が、これはすでにhere

関連する問題