Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.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
Json 用Jackson序列化和反序列化Lambda_Json_Serialization_Lambda_Java 8_Jackson - Fatal编程技术网

Json 用Jackson序列化和反序列化Lambda

Json 用Jackson序列化和反序列化Lambda,json,serialization,lambda,java-8,jackson,Json,Serialization,Lambda,Java 8,Jackson,我正在尝试序列化和反序列化一个类RuleMessage,但无法使其工作。这是我的密码: public class RuleMessage { private String id; private SerializableRunnable sRunnable; public RuleMessage(String id, SerializableRunnable sRunnable) { this.id = id; this.sRunnabl

我正在尝试序列化和反序列化一个类
RuleMessage
,但无法使其工作。这是我的密码:

public class RuleMessage {
    private String id;
    private SerializableRunnable sRunnable;

    public RuleMessage(String id, SerializableRunnable sRunnable) {
        this.id = id;
        this.sRunnable = sRunnable;
    }
}

我正在使用
Java8
。有人能告诉我这在
Jackson
库中是否可行吗?

首先,在RuleMessage中,您必须创建getter/setter或将字段公开,以便提供对字段的Jackson访问

然后,您的代码打印如下内容:

{"@class":"RuleMessage","id":"1","sRunnable":{"@class":"RuleMessage$$Lambda$20/0x0000000800b91c40"}}
new RuleMessage("1", new Runner())
无法反序列化此JSON文档,因为RuleMessage没有默认构造函数,并且无法构造lambda

您可以创建一个类,而不是lambda:

  public class Runner implements SerializableRunnable {
    @Override
    public void run() {
      System.out.println("Serializable!");
    }
  }

然后像这样构造您的pojo:

{"@class":"RuleMessage","id":"1","sRunnable":{"@class":"RuleMessage$$Lambda$20/0x0000000800b91c40"}}
new RuleMessage("1", new Runner())

Jackson反序列化程序现在可以重建对象并执行运行程序。

Jackson
创建的目的是保持对象状态不改变行为。这就是为什么它试图使用
getter
setter
等来序列化
POJO
的属性。序列化lambda打破了这个想法。没有任何要序列化的属性,只有一个应该调用的方法。序列化原始lambda对象真的是个坏主意,你们应该重新设计你们的应用程序以避免类似的用例

在您的例子中,
SerializableRunnable
接口扩展了
java.io.Serializable
,它提供了一个选项-。使用
java.io.ObjectOutputStream
我们可以将lambda对象序列化为字节数组,并使用
Base64
编码在
JSON
有效负载中对其进行序列化
Jackson
支持提供
writeBinary
getBinaryValue
方法的此场景

下面是一个简单的示例:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class JsonLambdaApp {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        SerializableRunnable action = () -> System.out.println("Serializable!");

        String json = mapper.writeValueAsString(new RuleMessage("1", action));
        System.out.println(json);

        RuleMessage ruleMessage = mapper.readValue(json, RuleMessage.class);
        ruleMessage.getsRunnable().run();
    }
}

@JsonSerialize(using = LambdaJsonSerializer.class)
@JsonDeserialize(using = LambdaJsonDeserializer.class)
interface SerializableRunnable extends Runnable, Serializable {
}

class LambdaJsonSerializer extends JsonSerializer<SerializableRunnable> {

    @Override
    public void serialize(SerializableRunnable value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream)) {
            outputStream.writeObject(value);
            gen.writeBinary(byteArrayOutputStream.toByteArray());
        }
    }
}

class LambdaJsonDeserializer extends JsonDeserializer<SerializableRunnable> {
    @Override
    public SerializableRunnable deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        byte[] value = p.getBinaryValue();
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(value);
             ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream)) {
            return (SerializableRunnable) inputStream.readObject();
        } catch (ClassNotFoundException e) {
            throw new IOException(e);
        }
    }
}

class RuleMessage {
    private String id;
    private SerializableRunnable sRunnable;

    @JsonCreator
    public RuleMessage(@JsonProperty("id") String id, @JsonProperty("sRunnable") SerializableRunnable sRunnable) {
        this.id = id;
        this.sRunnable = sRunnable;
    }

    public String getId() {
        return id;
    }

    public SerializableRunnable getsRunnable() {
        return sRunnable;
    }
}
和lambda:

Serializable!
另见:


首先,不能将Runnable作为参数传递。你已经使用了线程。谢谢你的回复。我确实有一个默认构造函数和getter/setter,为了简洁起见,我删除了它们(应该提到这一点)。我希望有一个灵活的设计,可以将方法调用封装在lambda函数中,并将其序列化到db中。稍后,我将反序列化lambda并调用它。我尝试在函数中实现该类,但Jackson无法序列化该类。如果我将类移到函数之外,效果会很好。在Jackson中有没有序列化内部类或lambda的方法?
Serializable!