简体   繁体   English

如何使用 Jackson 和包装器 object 反序列化/序列化字节数组

[英]how to deserialize / serialize byte array using Jackson and wrapper object

I have two following classes:我有以下两个课程:

public class User {

    private String name;

    private Secret secret;

    public User( @JsonProperty("name") String name, @JsonProperty("secret") Secret secret ) {
        this.name = name;
        this.secret = secret;
    }

    public String getName() {
        return name;
    }

    public Secret getSecret() {
        return secret;
    }

}

and

public class Secret {

    private byte[] secret;

    public Secret( byte[] secret ) {
        this.secret = secret;
    }

    @JsonValue
    public byte[] getSecret() {
        return secret;
    }

}

I would like to use these classes to serialize / deserialize following json:我想使用这些类来序列化/反序列化 json:

{
  "name": "bdf",
  "secret": "AQ=="
}

Java to json works properly. Java 到 json 工作正常。 However when I try to deserialize json I get the following exception:但是,当我尝试反序列化 json 时,出现以下异常:

com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class deserialization.Secret] from String value ('YQ=='); no single-String constructor/factory method
 at [Source: [B@3b938003; line: 1, column: 25] (through reference chain: deserialization.User["secret"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:875)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:281)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:284)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1176)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:143)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:134)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:461)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:376)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1099)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:294)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:131)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2807)
    at deserialization.SerializationTest.itShouldDeserialize(SerializationTest.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

How can I tell jackson to first decode base64 encoded value and then use this constructor?如何告诉 jackson 先解码 base64 编码值,然后使用此构造函数?

public Secret( byte[] secret )

This can be done by writing your own custom serializer and deserializer. 这可以通过编写自己的自定义序列化器和反序列化器来完成。

http://www.baeldung.com/jackson-custom-serialization http://www.baeldung.com/jackson-custom-serialization

http://www.baeldung.com/jackson-deserialization http://www.baeldung.com/jackson-deserialization

Here's an example similar to what you are doing... 这是一个与您正在执行的操作类似的示例...

Holder class 持有人类

public static class Holder {
    private Bytes bytes;
    private String otherStuff;

    public Bytes getBytes() {
        return bytes;
    }

    public void setBytes(Bytes bytes) {
        this.bytes = bytes;
    }

    public String getOtherStuff() {
        return otherStuff;
    }

    public void setOtherStuff(String otherStuff) {
        this.otherStuff = otherStuff;
    }

}

Bytes class 字节类

Notice the annotations for the custom serializer... 请注意自定义序列化程序的注释...

@JsonSerialize(using = BytesSerializer.class)
@JsonDeserialize(using = BytesDeserializer.class)
public static class Bytes {
    private byte[] bytes;

    public Bytes(byte[] bytes) {
        this.bytes = bytes;
    }

    public byte[] getBytes() {
        return bytes;
    }
}

Serializer 串行

This will serialize a "Bytes" object as a base64 string... 这会将“字节”对象序列化为base64字符串。

public static class BytesSerializer extends StdSerializer<Bytes> {

    private static final long serialVersionUID = -5510353102817291511L;

    public BytesSerializer() {
        super(Bytes.class);
    }

    @Override
    public void serialize(Bytes value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeString(Base64.encode(value.getBytes()));
    }
}

Deserializer 解串器

public static class BytesDeserializer extends StdDeserializer<Bytes> {

    private static final long serialVersionUID = 1514703510863497028L;

    public BytesDeserializer() {
        super(Bytes.class);
    }

    @Override
    public Bytes deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = p.getCodec().readTree(p);
        String base64 = node.asText();
        return new Bytes(Base64.decode(base64));
    }
}

Main method 主要方法

A simple test method... 一种简单的测试方法...

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();

    Holder holder = new Holder();
    holder.setOtherStuff("[OTHER STUFF]");
    holder.setBytes(new Bytes(new byte[] { 1, 2, 3, 4, 5 }));

    String json = mapper.writeValueAsString(holder);

    System.out.println(json);
    Holder deserialised = mapper.readValue(json, Holder.class);

    System.out.println(Arrays.toString(deserialised.getBytes().getBytes()));
}

Output 产量

{"bytes":"AQIDBAU=","otherStuff":"[OTHER STUFF]"}
[1, 2, 3, 4, 5]

Run it yourself 自己运行

All of the classes above are "static" because I'd wrapped them into one big class called "Stack". 上面的所有类都是“静态”的,因为我将它们包装到一个称为“堆栈”的大类中。

If you want to run this, create a new class (called anything you want) and paste all the code here into it... 如果要运行此代码,请创建一个新类(将其命名为您想要的任何东西)并将所有代码粘贴到其中...

I could not use a wrapped object, but I was able to figure out it wasn't necessary;我无法使用包装好的 object,但我发现这没有必要; the following works for me:以下对我有用:

public static class ByteArraySerializer extends StdSerializer<byte[]> {

    public ByteArraySerializer() {
        super(byte[].class);
    }

    @Override
    public void serialize(byte[] value, JsonGenerator gen,SerializerProvider provider) throws IOException {
        gen.writeString(Base64.getEncoder().encodeToString(value));
    }

}

public static class ByteArrayDeserializer extends StdDeserializer<byte[]> {

    private static final long serialVersionUID = 1514703510863497028L;

    public ByteArrayDeserializer() {
        super(byte[].class);
    }

    @Override
    public byte[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode node = p.getCodec().readTree(p);
        String base64 = node.asText();
        return Base64.getDecoder().decode(base64);
    }
}

public ObjectMapper getJsonMapper() {
    ObjectMapper jsonMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule("ByteArraySerializer", new Version(1, 0, 0, ""));
    module.addSerializer(byte[].class, new ByteArraySerializer());
    module.addDeserializer(byte[].class, new ByteArrayDeserializer());
    jsonMapper.registerModule(module);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Jackson:用一个数组字段序列化/反序列化 object - Jackson: serialize / deserialize object with one array field 使用 jackson 序列化和反序列化具有抽象字段的对象 - Serialize and deserialize an object with an abstract field using jackson 如何将Httpclient的响应object序列化和反序列化为字节数组 - How to serialize & deserialize response object of Httpclient into byte array 使用jackson序列化、反序列化 - Serialize, deserialize using jackson 如何配置杰克逊不序列化字节数组? - How to configure jackson to not to serialize byte array? 如何将内部没有 Serializable 字段的 java 对象序列化为字节数组并反序列化该数组以获取原始对象 - How to serialize a java object with not Serializable fields inside it into byte array and deserialize the array to get the original object 如何使用Jackson序列化/反序列化DefaultMutableTreeNode? - How to serialize/deserialize a DefaultMutableTreeNode with Jackson? 如何在不使用包装器对象的情况下反序列化前面带有前导标签的数组? - How to deserialize an array with leading label in front without using wrapper object? 通过网络和字节数组序列化/反序列化Java对象 - Serialize/Deserialize Java object through network and byte array Jackson 反序列化对象或数组 - Jackson deserialize object or array
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM