Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对接口类型使用Gson_Java_Json_Gson - Fatal编程技术网

Java 对接口类型使用Gson

Java 对接口类型使用Gson,java,json,gson,Java,Json,Gson,我正在编写一些服务器代码,其中客户端以JSON的形式发送请求。我的问题是,有许多可能的请求,在小的实现细节上都有所不同。 因此,我考虑使用一个请求接口,定义如下: public interface Request { Response process ( ); } 在此基础上,我在名为LoginRequest的类中实现了接口,如图所示: public class LoginRequest implements Request { private String type = "L

我正在编写一些服务器代码,其中客户端以JSON的形式发送请求。我的问题是,有许多可能的请求,在小的实现细节上都有所不同。 因此,我考虑使用一个请求接口,定义如下:

public interface Request {
    Response process ( );
}
在此基础上,我在名为
LoginRequest
的类中实现了接口,如图所示:

public class LoginRequest implements Request {
    private String type = "LOGIN";
    private String username;
    private String password;

    public LoginRequest(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * This method is what actually runs the login process, returning an
     * appropriate response depending on the outcome of the process.
     */
    @Override
    public Response process() {
        // TODO: Authenticate the user - Does username/password combo exist
        // TODO: If the user details are ok, create the Player and add to list of available players
        // TODO: Return a response indicating success or failure of the authentication
        return null;
    }

    @Override
    public String toString() {
        return "LoginRequest [type=" + type + ", username=" + username
            + ", password=" + password + "]";
    }
}
public class LoginRequestCreator implements InstanceCreator<LoginRequest> {
    @Override
    public LoginRequest createInstance(Type arg0) {
        return new LoginRequest("username", "password");
    }
}
为了使用JSON,我创建了一个
GsonBuilder
实例,并注册了一个
InstanceCreator
,如图所示:

public class LoginRequest implements Request {
    private String type = "LOGIN";
    private String username;
    private String password;

    public LoginRequest(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * This method is what actually runs the login process, returning an
     * appropriate response depending on the outcome of the process.
     */
    @Override
    public Response process() {
        // TODO: Authenticate the user - Does username/password combo exist
        // TODO: If the user details are ok, create the Player and add to list of available players
        // TODO: Return a response indicating success or failure of the authentication
        return null;
    }

    @Override
    public String toString() {
        return "LoginRequest [type=" + type + ", username=" + username
            + ", password=" + password + "]";
    }
}
public class LoginRequestCreator implements InstanceCreator<LoginRequest> {
    @Override
    public LoginRequest createInstance(Type arg0) {
        return new LoginRequest("username", "password");
    }
}
我得到了预期的输出

我希望做的事情是替换行
Request=parser.fromJson(completeInput,LoginRequest.class)类似于
Request-Request=parser.fromJson(completeInput,Request.class)但这样做不起作用,因为
请求
是一个接口

我希望我的
Gson
根据收到的JSON返回适当类型的请求

我传递给服务器的JSON示例如下所示:

{
    "type":"LOGIN",
    "username":"someuser",
    "password":"somepass"
}

重申一下,我正在寻找一种方法来解析来自客户端的请求(JSON),并返回实现
请求
接口的类的对象。默认情况下,GSON无法区分序列化为JSON的类;换句话说,您需要显式地告诉解析器您期望的是什么类


解决方案可以是自定义反序列化或使用类型适配器,如前所述。

所述类型的多态映射在没有某种自定义编码的Gson中不可用。有一个扩展类型适配器提供了您正在寻找的大部分功能,但需要注意的是,多态子类型需要提前声明给适配器。以下是其使用示例:

public interface Response {}

public interface Request {
    public Response process();
}

public class LoginRequest implements Request {
    private String userName;
    private String password;

    // Constructors, getters/setters, overrides
}

public class PingRequest implements Request {
    private String host;
    private Integer attempts;

    // Constructors, getters/setters, overrides
}

public class RequestTest {

    @Test
    public void testPolymorphicSerializeDeserializeWithGSON() throws Exception {
        final TypeToken<List<Request>> requestListTypeToken = new TypeToken<List<Request>>() {
        };

        final RuntimeTypeAdapterFactory<Request> typeFactory = RuntimeTypeAdapterFactory
                .of(Request.class, "type")
                .registerSubtype(LoginRequest.class)
                .registerSubtype(PingRequest.class);

        final Gson gson = new GsonBuilder().registerTypeAdapterFactory(
                typeFactory).create();

        final List<Request> requestList = Arrays.asList(new LoginRequest(
                "bob.villa", "passw0rd"), new LoginRequest("nantucket.jones",
                "crabdip"), new PingRequest("example.com", 5));

        final String serialized = gson.toJson(requestList,
                requestListTypeToken.getType());
        System.out.println("Original List: " + requestList);
        System.out.println("Serialized JSON: " + serialized);

        final List<Request> deserializedRequestList = gson.fromJson(serialized,
                requestListTypeToken.getType());

        System.out.println("Deserialized list: " + deserializedRequestList);
    }
}
公共接口响应{}
公共接口请求{
公众反应过程();
}
公共类LoginRequest实现请求{
私有字符串用户名;
私有字符串密码;
//构造函数、getter/setter、重写
}
公共类PingRequest实现请求{
私有字符串主机;
私有整数尝试;
//构造函数、getter/setter、重写
}
公共类请求测试{
@试验
public void testPolymorphicSerializeDeserializeWithGSON()引发异常{
final TypeToken requestListTypeToken=新的TypeToken(){
};
最终RuntimeTypeAdapterFactory类型工厂=RuntimeTypeAdapterFactory
.of(Request.class,“type”)
.registerSubtype(LoginRequest.class)
.registerSubtype(PingRequest.class);
final Gson Gson=new GsonBuilder().registerTypeAdapterFactory(
创建();
最终列表requestList=Arrays.asList(新登录请求(
“bob.villa”、“passw0rd”、新登录请求(“nantucket.jones”,
“crabdip”),新的PingRequest(“example.com”,5));
序列化的最终字符串=gson.toJson(requestList,
requestListTypeToken.getType());
System.out.println(“原始列表:“+requestList”);
System.out.println(“序列化JSON:+Serialized”);
最终列表反序列化dRequestList=gson.fromJson(序列化,
requestListTypeToken.getType());
System.out.println(“反序列化列表:“+deserializedRequestList”);
}
}
请注意,您实际上不需要在单个Java对象上定义
type
属性-它只存在于JSON中。

库默认提供对多态类型的支持。以下是它的工作原理:

// tell genson to enable polymorphic types support
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();

// json value will be {"@class":"mypackage.LoginRequest", ... other properties ...}
String json = genson.serialize(someRequest);
// the value of @class property will be used to detect that the concrete type is LoginRequest
Request request = genson.deserialize(json, Request.class);
您还可以为您的类型使用别名

// a better way to achieve the same thing would be to use an alias
// no need to use setWithClassMetadata(true) as when you add an alias Genson 
// will automatically enable the class metadata mechanism
genson = new Genson.Builder().addAlias("loginRequest", LoginRequest.class).create();

// output is {"@class":"loginRequest", ... other properties ...}
genson.serialize(someRequest);

假设您可能拥有的不同JSON请求彼此之间没有太大差异,我建议使用不同的方法,我认为更简单

假设您有以下3个不同的JSON请求:

{
    "type":"LOGIN",
    "username":"someuser",
    "password":"somepass"
}
////////////////////////////////
{
    "type":"SOMEREQUEST",
    "param1":"someValue",
    "param2":"someValue"
}
////////////////////////////////
{
    "type":"OTHERREQUEST",
    "param3":"someValue"
}
Gson允许您使用单个类来包装所有可能的响应,如下所示:

public class Request { 
  @SerializedName("type")   
  private String type;
  @SerializedName("username")
  private String username;
  @SerializedName("password")
  private String password;
  @SerializedName("param1")
  private String param1;
  @SerializedName("param2")
  private String param2;
  @SerializedName("param3")
  private String param3;
  //getters & setters
}
Gson gson = new Gson();
Request request = gson.fromJson(jsonString, Request.class);
通过使用注释
@SerializedName
,当Gson尝试解析JSON请求时,它只需查找类中每个命名属性的JSON请求中是否有同名字段。如果没有这样的字段,则类中的属性仅设置为
null

通过这种方式,您可以仅使用
请求
类解析许多不同的JSON响应,如下所示:

public class Request { 
  @SerializedName("type")   
  private String type;
  @SerializedName("username")
  private String username;
  @SerializedName("password")
  private String password;
  @SerializedName("param1")
  private String param1;
  @SerializedName("param2")
  private String param2;
  @SerializedName("param3")
  private String param3;
  //getters & setters
}
Gson gson = new Gson();
Request request = gson.fromJson(jsonString, Request.class);
一旦将JSON请求解析到类中,就可以将数据从wrap类传输到具体的
XxxxRequest
对象,类似于:

switch (request.getType()) {
  case "LOGIN":
    LoginRequest req = new LoginRequest(request.getUsername(), request.getPassword());
    break;
  case "SOMEREQUEST":
    SomeRequest req = new SomeRequest(request.getParam1(), request.getParam2());
    break;
  case "OTHERREQUEST":
    OtherRequest req = new OtherRequest(request.getParam3());
    break;
}

请注意,如果您有许多不同的JSON请求,并且这些请求彼此非常不同,那么这种方法会变得有点乏味,但即便如此,我认为这是一个很好且非常简单的方法…

我找到了这个答案:它解决了我在使用Calendar作为接口时的问题,因为运行时类型将是GregorianCalendar。

有一个实用方法为泛型接口创建GSON

//注册接口的实用方法及其在GSON中的实现

public static <T> Gson buildInterface(Class<T> interfaceType, List<Class<? extends T>> interfaceImplmentations) {
    final RuntimeTypeAdapterFactory<T> typeFactory = RuntimeTypeAdapterFactory.of(interfaceType, "type");
    for (Class<? extends T> implementation : interfaceImplmentations) {
        typeFactory.registerSubtype(implementation);
    }
    final Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeFactory).create();
    return gson;
}

公共静态Gson构建接口(Class interfaceType,List您可以提供其他您可以从服务器获得的不同JSON响应的示例吗?因为如果您没有太多和非常不同的可能性,有一些事情您可以轻松完成…感谢@MiKO的输入。其他可能的请求有
PlayRequest
LogoutRequest
GetPlayersRequest
JoinGameRequest
StartGameRequest
等等……我的意思是,如果您可以为至少一种其他类型的请求提供JSON请求的示例。我的意思是,对于您的
LoginRequest
,您有五个字段:
类型
用户名
密码
,其他请求如何它们看起来像吗?谢谢@MikO。我猜
开关盒
结构可能会进入某种请求工厂。谢谢。那就好了