我正在研究一些服务器代码,客户端以JSON的形式发送请求.我的问题是,有许多可能的请求,所有请求都在小的实现细节中有所不同.因此我想使用Request接口,定义如下:
public interface Request {
Response process ( );
}
Run Code Online (Sandbox Code Playgroud)
从那里,我在一个名为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 + "]";
}
}
Run Code Online (Sandbox Code Playgroud)
为了使用JSON,我创建了一个GsonBuilder
实例并注册了InstanceCreator
如下所示:
public class LoginRequestCreator implements InstanceCreator<LoginRequest> {
@Override
public LoginRequest createInstance(Type arg0) {
return new LoginRequest("username", "password");
}
}
Run Code Online (Sandbox Code Playgroud)
然后我使用如下面的代码段所示:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(LoginRequest.class, new LoginRequestCreator());
Gson parser = builder.create();
Request request = parser.fromJson(completeInput, LoginRequest.class);
System.out.println(request);
Run Code Online (Sandbox Code Playgroud)
我得到了预期的输出.
我想要做的是用Request request = parser.fromJson(completeInput, LoginRequest.class);
类似的东西替换行,Request request = parser.fromJson(completeInput, Request.class);
但这样做是行不通的,因为它Request
是一个接口.
我希望我Gson
根据收到的JSON返回相应类型的请求.
我传递给服务器的JSON示例如下所示:
{
"type":"LOGIN",
"username":"someuser",
"password":"somepass"
}
Run Code Online (Sandbox Code Playgroud)
重申一下,我正在寻找一种方法来解析客户端的请求(In JSON)并返回实现该Request
接口的类的对象
Per*_*ion 26
如果没有某种程度的自定义编码,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);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您实际上不需要type
在单个Java对象上定义属性 - 它仅存在于JSON中.
假设您可能拥有的不同可能的JSON请求彼此之间没有太大的不同,我建议采用不同的方法,在我看来更简单.
假设您有以下3种不同的JSON请求:
{
"type":"LOGIN",
"username":"someuser",
"password":"somepass"
}
////////////////////////////////
{
"type":"SOMEREQUEST",
"param1":"someValue",
"param2":"someValue"
}
////////////////////////////////
{
"type":"OTHERREQUEST",
"param3":"someValue"
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
通过使用注释@SerializedName
,当Gson尝试解析JSON请求时,它只是为类中的每个命名属性查看JSON请求中是否存在具有相同名称的字段.如果没有这样的字段,则类中的属性只是设置为null
.
这样,您只需使用您的Request
类即可解析许多不同的JSON响应,如下所示:
Gson gson = new Gson();
Request request = gson.fromJson(jsonString, Request.class);
Run Code Online (Sandbox Code Playgroud)
将JSON请求解析到类中后,可以将数据从包装类传输到具体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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您有许多不同的JSON请求并且这些请求彼此非常不同,这种方法会变得有点繁琐,但即便如此,我认为这是一种很好且非常简单的方法......
归档时间: |
|
查看次数: |
16054 次 |
最近记录: |