首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Infinispan和computeIfAbsent的无效lambda反序列化

使用Infinispan和computeIfAbsent的无效lambda反序列化
EN

Stack Overflow用户
提问于 2019-04-01 14:27:00
回答 1查看 691关注 0票数 2

我在玩basic无穷大集群,遇到了一个令人费解的错误。

我基本上是在实现一个共享的地图,只保存一个整数

这是我的服务代码

代码语言:javascript
复制
package sandbox.infinispan.test.service;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.infinispan.Cache;

@Named("useThisOne")
@ApplicationScoped
public class CounterService implements ICounterService {

    private static final String KEY = "key";

    @Inject
    private Cache<String, Integer> cache;

    @Override
    public void inc(final int amount) {
        this.cache.put(KEY, Integer.valueOf(this.get() + amount));
    }

    @Override
    public int get() {
        return this.cache.computeIfAbsent(KEY, k -> Integer.valueOf(0)).intValue();
    }
}

缓存由以下内容生成:

代码语言:javascript
复制
package sandbox.infinispan.test.config;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;

import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;

@Dependent
class CacheProvider {

    @Produces
    @ApplicationScoped
    private EmbeddedCacheManager defaultClusteredCacheManager() {
        final GlobalConfiguration g = new GlobalConfigurationBuilder() //
                .clusteredDefault() //
                .transport() //
                .nodeName(this.getNodeName()) //
                .clusterName("infinispanTestCluster") //
                .build();
        final Configuration cfg = new ConfigurationBuilder() //
                .clustering() //
                .cacheMode(CacheMode.REPL_SYNC) ///
                .build();
        return new DefaultCacheManager(g, cfg);
    }
}

当集群中至少有两个服务器时,computeIfAbsent将失败

代码语言:javascript
复制
15:48:50,253 ERROR [org.infinispan.interceptors.impl.InvocationContextInterceptor] (jgroups-7,myhostname-14393) ISPN000136: Error executing command ComputeIfAbsentCommand, writing keys [key]: org.infinispan.remoting.RemoteException: ISPN000217: Received exception from otherhostname-44445, see cause for remote stack trace

具体到以下几点:

代码语言:javascript
复制
Caused by: java.lang.NoSuchMethodException: sandbox.infinispan.test.service.CounterService.$deserializeLambda$(java.lang.invoke.SerializedLambda)

最后要:

代码语言:javascript
复制
Caused by: java.lang.IllegalArgumentException: Invalid lambda deserialization
        at sandbox.infinispan.test.service.CounterService.$deserializeLambda$(CounterService.java:10)
            ... 68 more
Caused by: an exception which occurred:
        in object of type java.lang.invoke.SerializedLambda

如果我把我漂亮的时尚代码重写给丑陋的追随者,它就能工作了。

代码语言:javascript
复制
@Override
public int get() {
    Integer value = this.cache.get(KEY);
    if (value == null) {
        value = Integer.valueOf(0);
        this.cache.put(KEY, value);
    }
    return value.intValue();
}

我现在怎样才能用漂亮的computeIfAbsent方式做事呢?

Eclipse2018-12、WildFly 14、java 10对集群的dev成员、CentOs 7、OpenJdk 10、远程集群成员的WildFly 14。

谢谢你的帮忙

解决了(有点)

由于我在这里得到了帮助,我将lambda转化为一个内部类:

代码语言:javascript
复制
static class OhWell implements Serializable {

    static Integer zero(final String t) {
        return Integer.valueOf(0);
    }
}

@Override
public int get() {
    return this.cache.computeIfAbsent(KEY, OhWell::zero).intValue();
}

它现在起作用了,但它比整洁的羔羊好多了。所以我会坚持传统的方法除非有人能想出更好的方法。

进一步结果:

下面的静态内部类与静态方法一起工作

代码语言:javascript
复制
static class StaticOhWell implements Serializable {

    static Integer apply(final String t) {
        return Integer.valueOf(0);
    }
}

@Override
public int get() {
    return this.cache.computeIfAbsent(KEY, StaticOhWell::apply).intValue();
}

以下具有非静态方法的非静态内部类失败:

代码语言:javascript
复制
class NotStaticOhWell implements SerializableFunction<String, Integer> {

    @Override
    public Integer apply(final String t) {
            return Integer.valueOf(0);
    }
}

@Override
public int get() {
    return this.cache.computeIfAbsent(KEY, new NotStaticOhWell()::apply).intValue();
}

它在此错误消息NotSerializableException: NotSerializableException中失败

代码语言:javascript
复制
13:41:29,221 ERROR [org.infinispan.interceptors.impl.InvocationContextInterceptor] (default task-1) ISPN000136: Error executing command ComputeIfAbsentCommand, writing keys [value]: org.infinispan.commons.marshall.NotSerializableException: org.infinispan.cache.impl.EncoderCache
    Caused by: an exception which occurred:
    in field sandbox.infinispan.test.service.CounterService.cache
    in object sandbox.infinispan.test.service.CounterService@4612a6c3
    in field sandbox.infinispan.test.service.CounterService$NotStaticOhWell.this$0
    in object sandbox.infinispan.test.service.CounterService$NotStaticOhWell@4effd362
    in field java.lang.invoke.SerializedLambda.capturedArgs
    in object java.lang.invoke.SerializedLambda@e62f08a
    in object sandbox.infinispan.test.service.CounterService$$Lambda$1195/1060417313@174a143b

终结词(?)

使用“静态lambda”(实现SerializableFunction接口的静态内部类)也有效。

代码语言:javascript
复制
static class StaticSerializableFunction implements SerializableFunction<String, Integer> {

    @Override
    public Integer apply(final String t) {
        return Integer.valueOf(0);
    }
}

@Override
public int get() {
    return this.cache.computeIfAbsent(KEY, new StaticSerializableFunction()::apply).intValue();
}

和获胜者是…

通过Cache允许简单地使用该类的一个方法,通过“临时”使类实际上可以序列化。不需要创建一个内部类!

代码语言:javascript
复制
package sandbox.infinispan.test.service;

import java.io.Serializable;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.infinispan.Cache;

@Named("useThisOne")
@ApplicationScoped
public class CounterService implements ICounterService, Serializable {

    private static final String KEY = "value";

    @SuppressWarnings("cdi-ambiguous-dependency")
    @Inject
    private transient Cache<String, Integer> cache;

    @Override
    public void inc(final int amount) {
        this.cache.put(KEY, Integer.valueOf(this.get() + amount));
    }

    @Override
    public int get() {
        return this.cache.computeIfAbsent(KEY, this::zero).intValue();
    }

    private Integer zero(@SuppressWarnings("unused") final String unused) {
        return Integer.valueOf(0);
    }

    @Override
    public void reset() {
        this.cache.clear();
    }
}

谢谢大家!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-02 07:02:24

根据Unable to deserialize lambda,反序列化程序需要实际的代码才能可用。您是否确定您的应用程序已经在集群中的所有其他节点上启动(完全相同的版本,包括您的lambda)?

computeIfAbsent()将lambda直接发送到数据(因此使用一个RPC来处理操作,而不是首先获取值,然后将其写成“丑陋的代码”)。在WF中,您的应用程序生活在与Infinispan不同的类加载器(模块)中,这可能会导致问题。

你能否尝试将你的lambda重构成一个类,看看你是否遇到了类似的问题?我对WF不太了解,所以对于普通类可能有一个缓解措施,而lambdas则没有这样的效果。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55457482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档