Java 代码设计:从套接字到自定义处理程序类的JSON
我有一个Java的套接字服务器。此套接字将接收具有特定结构的json字符串Java 代码设计:从套接字到自定义处理程序类的JSON,java,json,generics,gson,guice,Java,Json,Generics,Gson,Guice,我有一个Java的套接字服务器。此套接字将接收具有特定结构的json字符串 { "command": "test", "name": "Hallo Welt" } 我不能改变这种结构。“command”的值将声明内容的类型 从套接字接收到该命令后,我想调用不同的处理程序来处理这些不同的命令: 命令“test”>TestHandler实现CommandHandler 命令“foo”>foodhandler实现CommandHandler 如何将json转换为对象并将该对象绑定
{
"command": "test",
"name": "Hallo Welt"
}
我不能改变这种结构。“command”的值将声明内容的类型
从套接字接收到该命令后,我想调用不同的处理程序来处理这些不同的命令:
- 命令“test”>TestHandler实现CommandHandler
- 命令“foo”>foodhandler实现CommandHandler
class BaseCommand {
public CommandType command;
}
class TestCommand extends BaseCommand {
public String name;
}
使用GSON,我将JSON解析为BaseCommand类。
之后,我可以读取命令类型
我声明一个枚举以将命令类型映射到处理程序:
enum CommandType {
test(TestHandler.class),
foo(FooHandler.class);
public final Class<? extends CommandHandler> handlerClass;
public CommandTypes(Class<? extends CommandHandler> handlerClass) {
this.handlerClass = handlerClass;
}
}
enum命令类型{
test(TestHandler.class),
foo(foodhandler.class);
公开期末班
如何获取CommandModel?
如果commandType为“test”,如何自动解析TestCommand
您可以使用TypeAdapterFactory
以最准确和灵活的方式获取最合适的类型适配器。下面的示例与您的类命名略有不同,但我认为这对您来说不是什么大问题。因此,假设您有以下命令参数DTO声明:
抽象类AbstractCommandDto{
最终字符串命令=null;
}
最终类HelloCommandDto
将命令扩展到{
最终字符串名称=null;
}
现在,您可以创建一个特殊的TypeAdapterFactory
,通过命令参数名称预先确定传入的命令。它可能看起来很复杂,但实际上TypeAdapterFactory
ies并不是很难实现。请注意,JsonDeserializer
可能是您的另一个选项,但您会失败自动反序列化,除非您将其反序列化()
方法委托给另一个备份Gson
实例
final类AbstractCommandToTypeAdapterFactory
实现TypeAdapterFactory{
//工厂不处理任何状态,可以实例化一次
私有静态最终类型适配器工厂AbstractCommandtTypeAdapterFactory=新的AbstractCommandtTypeAdapterFactory();
//类型标记用于定义类型信息,是完美的值类型,因此它们也可以实例化一次
私有静态最终类型令牌abstractCommandProbingDtoTypeToken=新类型令牌(){
};
私有静态最终类型令牌HelloCommand和DtoTypeToken=新类型令牌(){
};
私有AbstractCommandTypeAdapterFactory(){
}
静态TypeAdapterFactory GetAbstractCommandToTypeAdapterFactory(){
返回AbstractCommandToTypeAdapterFactory;
}
@凌驾
公共类型适配器创建(最终Gson Gson、最终TypeToken TypeToken){
//首先,检查传入类型是否为AbstractCommandDto
if(AbstractCommandTo.class.isAssignableFrom(typeToken.getRawType())){
//如果是,则为混凝土类型构建一个特殊类型适配器
最终类型适配器AbstractCommandtTypeAdapter=新的AbstractCommandtTypeAdapter(
格森,
getDelegateAdapter(这是abstractCommandProbingDtoTypeToken),
(commandName,jsonObject)->反序列化(gson,commandName,jsonObject),
dto->getTypeAdapter(gson,dto)
);
//javac的一些欺骗行为。。。
@抑制警告(“未选中”)
final TypeAdapter TypeAdapter=(TypeAdapter)AbstractCommandToTypeAdapter;
返回类型适配器;
}
//如果是其他原因,就让Gson选择下一个类型适配器
返回null;
}
//从一个随时可用的JsonObject创建一个AbstractCommandDto实例(参见下面关于JSON树的缺点)
要反序列化的私有AbstractCommandDto(最终Gson Gson、最终字符串commandName、最终JsonObject JsonObject){
@抑制警告(“未选中”)
最终的TypeToken TypeToken=(TypeToken)解析(commandName);
final-TypeAdapter-TypeAdapter=gson.getDelegateAdapter(这个,typeToken);
从JSONTREE(jsonObject)返回typeAdapter.fromJsonTree;
}
私有类型适配器getTypeAdapter(最终Gson Gson,最终AbstractCommandDto dto){
@抑制警告(“未选中”)
最终类clazz=(类)dto.getClass();
返回gson.getDelegateAdapter(this,TypeToken.get(clazz));
}
//这只是为了简单起见,甚至可以从类型适配器工厂类的其他地方提取
私有静态TypeToken,Consumer>commandRegistry=new LinkedHashMap();
commandRegistry.put(HelloCommandDto.class,新的HelloCommand());
//模拟并接受请求
final AbstractCommandDto AbstractCommandDto=gson.fromJson(“{\”命令\“:\”你好\“,”名字\“:\”世界\“}”,AbstractCommandDto.class);
//解析命令
最终使用者命令=commandRegistry.get(abstractCommandDto.getClass());
如果(命令==null){
抛出新的IllegalArgumentException(“无法处理”+AbstractCommandTo.command);
}
//派遣
@抑制警告(“未选中”)
最终使用者命令=(使用者)命令;
接受(abstractCommandDto);
//模拟反应
System.out.println(gson.toJson(abstractCommandDto));
}
私有静态最终类HelloCommand
实施消费者{
@凌驾
公共无效接受(最终Hello命令至Hello命令){
System.out.println(“Hallo”+helloCommandDto.name);
}
}
输出:
哈罗贴边
public interface CommandHandler<T extends BaseCommand> {
void handle(T command);
}
// in class ...
private final Map<CommandType, CommandHandler> handlers;
@Inject ClassName(Map<CommandType, CommandHandler> handlers) {
this.handlers = handlers;
}
// in converter method
private void convert(String json) {
BaseCommand baseCommand = GSONHelper().fromJson(json, BaseCommand.class);
// How can I get the CommandModel?
// If the commandType is "test" how can I parse TestCommand automatically?
??? commandModel = GSONHelper().fromJson(json, ???);
handlers.get(baseCommand.command).handle(commandModel);
}