Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.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 如何使用jacksonmixin将Json映射到Proto?_Java_Json_Jackson_Protocol Buffers_Jackson Databind - Fatal编程技术网

Java 如何使用jacksonmixin将Json映射到Proto?

Java 如何使用jacksonmixin将Json映射到Proto?,java,json,jackson,protocol-buffers,jackson-databind,Java,Json,Jackson,Protocol Buffers,Jackson Databind,我们在一个后端应用程序中使用Protobuffers作为model/pojo文件。 我们必须调用API,它以JSON的形式返回响应 我正在寻找一种将JSON文件直接映射到proto的解决方案。java文件。 例如,我们的项目中有示例proto: message Example{ string id = 1; string another_id = 2; int32 code = 3; stri

我们在一个后端应用程序中使用
Protobuffers
作为model/pojo文件。 我们必须调用
API
,它以
JSON
的形式返回响应

我正在寻找一种将
JSON
文件直接映射到proto的解决方案。java文件。 例如,我们的项目中有示例proto:

message Example{
 string id                    = 1;
 string another_id            = 2;
 int32 code                   = 3;
 string name                 = 4;
}
现在我们需要调用一个
API
,它以
JSON
返回响应:

{
   "json_id":"3",
   "json_another_id":"43",
   "code":34,
   "json_name":"Yeyproto"
}
现在,我想直接用Proto映射响应(json格式)。 请让我知道怎么做。请注意,由于Example.java是一个自动生成的java文件,因此我无法对此类进行任何更改。另外,请注意json和proto的字段是不同的

这是我试过的。 我尝试使用Jackson Mixin并将映射信息保留在Mixin类中,但没有成功,并抛出了一些奇怪的FieldDescriptor错误

public abstract class UserMixin { 
    @JsonProperty("json_id")
    String id;

    @JsonProperty("json_another_id")
    String another_id;

    @JsonProperty("code")
    int code;

    @JsonProperty("json_name")
    String name;
}
用法和示例:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Example.class, ExampleMixin.class);
Position usr = objectMapper.readerFor(Example.class).readValue(json);
System.out.println(json);
例外情况:

om.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法 查找类型[简单类型,类]的(映射)键反序列化器 com.google.protobuf.descriptor$FieldDescriptor]


请帮我找到解决这个问题的好方法。

protoc
编译器生成的类不是简单的
POJO
。它们包含许多不同的方法和类型,我们需要“过滤”以使
Jackson
工作

固定
MixIn
class 事实上,有一个比自定义反序列化程序更简单的解决方案。您需要忽略
映射getAllFields()
方法,并通过添加下划线来改进字段名:
\uuu

例如:

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();
}
自定义反序列化程序+
com.hubspot
library 在这种情况下,最简单的解决方案是为所有
com.google.protobuf.
类型编写一组反序列化器和序列化器,这些类型被编译成
POJO
。幸运的是,已经实现了处理它们的模块:

您案例中的示例用法如下所示:

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();
    }
}
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>

com.fasterxml.jackson.core
杰克逊数据绑定
2.10.0
com.google.protobuf
protobuf java
3.11.0
com.hubspot.jackson
jackson数据类型协议
0.9.11-jackson2.9

这是使用
protobuf java util
库将Json反序列化为Proto的另一个示例:

        File file = new File("src/test/resources/ACDSResponse.json");
        Reader bufferedReader = new BufferedReader(new FileReader(file));
        Acds.GetLocalizedAttributesBatchResponse.Builder acdsResponseBuilder = Acds.GetLocalizedAttributesBatchResponse.newBuilder();
        JsonFormat.parser().ignoringUnknownFields().merge(bufferedReader, acdsResponseBuilder);``

嗨,谢谢你的回复。但是您基本上调用setter和getter来创建Example.java Example.newBuilder().setId(root.get(“json_id”).asText()).setAnotherId(root.get(“json_另一个_id”).asText()).setName(root.get(“json_name”).asText()).setCode(root.get(“json_id”).asInt()).build()我正在寻找一个解决方案,我们可以有一个映射外部。我们不必显式地调用getter和setters@AvinashKharche,你所说的“外部有映射”是什么意思?在您的示例中,使用MixIn类。你能解释一下最好的解决方案是什么样的吗?当然,您可以在转换为
Example
之前替换名称,然后只有
ProtobufModule
模块就足够了。1。“具有外部映射”-我的意思是其他一些类或文件应该具有json和proto之间的映射定义。类似于这个json_id->id在我的示例中,我使用的是一个抽象的mixin类,使用这个类的好处是,如果我们收到新的映射/属性,那么我们不需要更改任何代码,只需要更改映射文件2。如何更改json密钥的名称正是问题所在。如果密钥匹配很容易将json转换为proto,也可以使用JsonFormatter@AvinashKharche,使用
MixIn
功能是一种正确的方法。它只是需要一些改进。看看最新的答案。谢谢@MichalZiober,这对Mixin很有效。我相信Mixin是一个很好的解决方案。你怎么认为?
<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>
        File file = new File("src/test/resources/ACDSResponse.json");
        Reader bufferedReader = new BufferedReader(new FileReader(file));
        Acds.GetLocalizedAttributesBatchResponse.Builder acdsResponseBuilder = Acds.GetLocalizedAttributesBatchResponse.newBuilder();
        JsonFormat.parser().ignoringUnknownFields().merge(bufferedReader, acdsResponseBuilder);``