首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在为Jinq创建查询时可以使用Predicate<T>吗?

在为Jinq创建查询时可以使用Predicate<T>吗?
EN

Stack Overflow用户
提问于 2016-01-16 02:42:54
回答 1查看 552关注 0票数 2

我的问题是关于Jinq的,我使用的是版本1.8.9,这是最新的版本。

我试图使用Jinq实现一个通用的可重用的JPA () typesafe查询方法,方法参数是Java 8 lambda (functional )谓词。

不幸的是,我无法使它与Java 8谓词一起工作,而是可以使用类似的谓词类型(由Jinq提供)作为方法参数,但希望避免方法签名中对Jinq的依赖,因此如果可能的话会更喜欢Java 8谓词吗?

Jinq提供了“其中”的功能接口:

代码语言:javascript
复制
package org.jinq.orm.stream;
public interface JinqStream<T> extends Stream<T> {
    @FunctionalInterface
    public static interface Where<U, E extends Exception> extends Serializable {
      public boolean where(U obj) throws E;
    }

我可以通过在方法签名中使用上面的接口来实现我想要的查询方法(但使用不希望的耦合),如下所示:

代码语言:javascript
复制
public List<T> select(JinqStream.Where<T, Exception> wherePredicate)

与上述方法签名中的Jinq耦合不同,我想使用标准谓词,如下所示:

代码语言:javascript
复制
public List<T> select(java.util.function.Predicate<T> wherePredicate) {

标准谓词的定义如下:

代码语言:javascript
复制
@FunctionalInterface
public interface Predicate<T> {
  public boolean test(T t);
}

因此,我认为可以使用以下代码实现我想要的select方法,用于创建Jinq接口的lambda实现:

代码语言:javascript
复制
public List<T> select(java.util.function.Predicate<T> predicate) {
    org.jinq.orm.stream.JinqStream.Where<T, Exception> wherePredicate = u -> predicate.test(u);
    ...

但是,它不起作用,但会导致IllegalArgumentException (请参阅下面粘贴的堆栈跟踪)。

下面是一些更多的代码,说明我正在尝试做什么。

我试图说明的问题是,我希望在下面的方法"DataMapperBase.select2“中使用谓词参数,而不是像下面的方法"DataMapperBase.select”那样使用Jinq特定的Where参数。

代码语言:javascript
复制
public abstract class DataMapperBase<T> {
    ...
    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private final Class clazz;// initialized using below method getClazz()

    private Class getClazz() throws ClassNotFoundException {
        Type genericSuperclass = getClass().getGenericSuperclass();
        Type actualTypeArgument = ((ParameterizedType)genericSuperclass).getActualTypeArguments()[0];
        return Class.forName(actualTypeArgument.getTypeName());
    }

    // This method works but has an undesirable dependency to Jinq in method signature.
    public List<T> select(org.jinq.orm.stream.JinqStream.Where<T, RuntimeException> wherePredicate) {
        JinqJPAStreamProvider streams = new JinqJPAStreamProvider(entityManagerFactory);
        List<T> result = streams
          .streamAll(entityManager, clazz)
          .where( wherePredicate )
          .toList();
        return result;
    }    

    // Instead of the above select method I want to use the below method (currently named "select2")

    // The code below compiles but does not work in runtime.This is the method signature I would like to use.
    public List<T> select2(java.util.function.Predicate<T> predicate) {
        org.jinq.orm.stream.JinqStream.Where<T, RuntimeException> wherePredicate = u -> predicate.test(u);    
        JinqJPAStreamProvider streams = new JinqJPAStreamProvider(entityManagerFactory);
        List<T> result = streams
          .streamAll(entityManager, clazz)
          .where( wherePredicate )
          .toList();
        return result;
    }
...
public class PersonDataMapper extends DataMapperBase<Person> { ...
...
@Entity
@Access(AccessType.PROPERTY)
@Table(name="person")
public class Person implements Serializable {
    ...
    private int age;
    @Column(name = "Age")
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    ...

...
// The invocations below can be used e.g. from a test class
List<Person> persons  = personDataMapper.select( p -> p.getAge() > 20 );
List<Person> persons2 = personDataMapper.select2( p -> p.getAge() > 20 );

上述两种方法(select和select2)都会编译,但第二种方法在运行时失败,只有以下例外;

代码语言:javascript
复制
java.lang.IllegalArgumentException: Could not extract code from lambda. This error sometimes occurs because your lambda references objects that aren't Serializable.
    at org.jinq.jpa.transform.LambdaInfo.analyze(LambdaInfo.java:33)
    at org.jinq.jpa.transform.LambdaAnalysisFactory.extractSurfaceInfo(LambdaAnalysisFactory.java:7)
    at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:269)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:365)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:1)
    at org.jinq.orm.stream.QueryJinqStream.where(QueryJinqStream.java:45)
    at org.jinq.jpa.QueryJPAJinqStream.where(QueryJPAJinqStream.java:86)

错误消息指出,可能是java.util.function.Predicate无法实现可序列化的问题。(因为我的示例中的人员实现了可序列化)

不过,然后我尝试了另一个界面,如:

代码语言:javascript
复制
public interface Predicate2<T> extends java.util.function.Predicate<T> , Serializable {}

当我使用它时,我得到了以下例外:

代码语言:javascript
复制
java.lang.IllegalArgumentException: Could not analyze lambda code
    at org.jinq.jpa.transform.LambdaAnalysis.fullyAnalyzeLambda(LambdaAnalysis.java:197)
    at org.jinq.jpa.transform.LambdaInfo.fullyAnalyze(LambdaInfo.java:116)
    at org.jinq.jpa.JPAQueryComposer.applyTransformWithLambda(JPAQueryComposer.java:278)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:365)
    at org.jinq.jpa.JPAQueryComposer.where(JPAQueryComposer.java:1)
    at org.jinq.orm.stream.QueryJinqStream.where(QueryJinqStream.java:45)
    at org.jinq.jpa.QueryJPAJinqStream.where(QueryJPAJinqStream.java:86)    

那么,我的问题是,是否有人可以提供上述方法"DataMapperBase.select2“的工作实现,即使用参数java.util.function.Predicate的方法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-16 15:14:50

由于Java 8实现lambdas的局限性,Jinq需要使用Serializable lambda。不幸的是,Java8中的默认Predicate不是可序列化的,因此不能由Jinq进行分析。

去年,我在JVM语言峰会上就Jinq的工作方式进行了一次演讲。关于为什么Jinq不能使用默认的Java 8 Predicate的部分将在17:16的范围内进行讨论:

https://youtu.be/JqCnZFzTR2I?t=17m16s

当前的Jinq字节码分析目前主要设计为使用Jinq查询样式,因此如果您试图填充任意的lambdas,Jinq的分析可能会失败。视频中的其他部分也讨论了这一点。

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

https://stackoverflow.com/questions/34822975

复制
相关文章

相似问题

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