protoc 编译器生成的类并不简单POJO。它们包含许多我们需要“过滤掉”以使Jackson 工作的不同方法和类型。
修复MixIn类
确实有比自定义反序列化器更简单的解决方案。您需要忽略Map<Descriptors.FieldDescriptor, Object> getAllFields() 方法并通过添加下划线来改进字段名称:_。
例子:
import com.celoxity.protobuf.ExampleOuterClass.Example;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Timestamp;
import java.time.Instant;
import java.util.Map;
public class ProtobufApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addMixIn(Example.class, ExampleMixin.class)
.addMixIn(Timestamp.class, TimestampMixin.class)
.build();
String json = "{" +
"\"json_id\":\"3\"," +
"\"json_another_id\":\"43\"," +
"\"code\":34," +
"\"json_name\":\"Yeyproto\"," +
"\"currTime\":{\"seconds\":1575909372,\"nanos\":35000000}" +
"}";
Example deserialised = mapper.readValue(json, Example.class);
System.out.println(deserialised);
Timestamp currTime = deserialised.getCurrTime();
System.out.println(Instant.ofEpochSecond(currTime.getSeconds(), currTime.getNanos()));
}
}
abstract class ExampleMixin extends ProtoBufIgnoredMethods {
@JsonProperty("json_id")
String id_;
@JsonProperty("json_another_id")
String anotherId_;
@JsonProperty("code")
int code_;
@JsonProperty("json_name")
String name_;
@JsonProperty("currTime")
Timestamp currTime_;
}
abstract class TimestampMixin extends ProtoBufIgnoredMethods {
@JsonProperty("seconds")
String seconds_;
@JsonProperty("nanos")
String nanos_;
}
abstract class ProtoBufIgnoredMethods {
@JsonIgnore
public abstract Map<Descriptors.FieldDescriptor, Object> getAllFields();
}
上面的代码打印:
id: "3"
another_id: "43"
code: 34
name: "Yeyproto"
currTime {
seconds: 1575909372
nanos: 35000000
}
2019-12-09T16:36:12.035Z
自定义反序列化器 + com.hubspot 库
在这种情况下,最简单的解决方案是编写一组反序列化器,并将所有com.google.protobuf.*类型的序列化器编译成POJO。幸运的是,已经实现了处理它们的模块:jackson-datatype-protobuf。
您的示例用法如下所示:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.hubspot.jackson.datatype.protobuf.ProtobufModule;
import java.io.IOException;
public class ProtobufApp {
public static void main(String[] args) throws Exception {
SimpleModule pojosModule = new SimpleModule();
pojosModule.addDeserializer(Example.class, new ExampleJsonDeserializer());
ObjectMapper mapper = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new ProtobufModule())
.addModule(pojosModule)
.build();
String json = "{\"json_id\":\"3\",\"json_another_id\":\"43\",\"code\":34,\"json_name\":\"Yeyproto\"}";
Example deserialised = mapper.readValue(json, Example.class);
System.out.println(deserialised);
}
}
class ExampleJsonDeserializer extends JsonDeserializer<Example> {
@Override
public Example deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectNode root = p.readValueAsTree();
return Example.newBuilder()
.setId(root.get("json_id").asText())
.setAnotherId(root.get("json_another_id").asText())
.setName(root.get("json_name").asText())
.setCode(root.get("json_id").asInt())
.build();
}
}
示例代码打印:
id: "3"
another_id: "43"
code: 3
name: "Yeyproto"
Maven 依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.hubspot.jackson</groupId>
<artifactId>jackson-datatype-protobuf</artifactId>
<version>0.9.11-jackson2.9</version>
</dependency>