gpt4 book ai didi

java - Spring Query DSL 给出空指针异常

转载 作者:行者123 更新时间:2023-11-30 06:19:33 25 4
gpt4 key购买 nike

我在此原型(prototype)中使用 Spring Boot 和 Hibernate 文件数据库。

这是 application.properties 中的一个片段(省略了用户/密码。显然)注意我已将 fave 设置为字符串而不是 boolean 值,因此我可以在查询 DSL 绑定(bind)中使用字符串:

spring.jpa.generate-ddl=true
spring.datasource.url=jdbc:h2:file:~/db
spring.datasource.driver-class-name=org.h2.Driver
hibernate.hbm2ddl.auto=update
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=true

这是省略了 City 类的模型,因为它非常简单:

@Data
@AllArgsConstructor
@Entity
@Table(name = "matches")
@EqualsAndHashCode(of = "id")
public class FilterMatch {

@SequenceGenerator(name = "MATCHES_SEQ_GENERATOR", sequenceName = "MATCHES_SEQ",
initialValue = 1, allocationSize = 1)

@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "MATCHES_SEQ_GENERATOR")
@Column
private Long id;

@Column
private String fave;

@Column
private int age;

@Column
private int cmHeight;

@Column
private int contactsExchanged;

@Column
private float compatScore;

@Column
private String displayName;

@Column
private String jobTitle;

@Column
private String mainPhoto;

@Column
private String religion;

@OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
private City city;

public FilterMatch() {}

// getters/setters omitted
}

这是根据需要扩展 JPARepository 的存储库:

public interface FilterMatchRepository extends JpaRepository<FilterMatch, Long>,
QueryDslPredicateExecutor<FilterMatch>,QuerydslBinderCustomizer<QFilterMatch> {


@Override
default public void customize(QuerydslBindings bindings, QFilterMatch root) {
bindings.bind(String.class)
.first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase);
bindings.excluding(root.religion,root.jobTitle);
}

}

我的 SearchCriteria 类:

public class SearchCriteria {

private static final Logger logger = LogManager.getLogger(SearchCriteria.class);

private String key;
private String operation;
private Object value;

public SearchCriteria(String key, String operation, Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
//getters & setters omitted.
}

我的 MatchBuilderPredicates 类和我的 MatchPredicates 类:

public class MatchPredicatesBuilder {

private static final Logger logger = LoggerFactory.getLogger(MatchPredicatesBuilder.class);

private List<SearchCriteria> parameters;

public MatchPredicatesBuilder() {
parameters = new ArrayList<>();
}

public MatchPredicatesBuilder with(String key, String operation, Object value) {

parameters.add(new SearchCriteria(key, operation, value));
return this;
}

public BooleanExpression build() {

if (parameters.size() == 0) {
return null;
}

List<BooleanExpression> predicates = new ArrayList<>();
MatchPredicate predicate;

for (SearchCriteria param : parameters) {

predicate = new MatchPredicate(param);
BooleanExpression expression = predicate.getPredicate();

if (Objects.nonNull(expression)) {
predicates.add(expression);
}
}

BooleanExpression result = predicates.get(0);

for (int i = 1; i < predicates.size(); i++) {

result = result.and(predicates.get(i));
}
return result;
}

}

public class MatchPredicate {

private static final long serialVersionUID = 8621295752447527269L;
private static final Logger logger = LoggerFactory.getLogger(MatchPredicate.class);

private SearchCriteria criteria;

public MatchPredicate(SearchCriteria criteria) {
this.criteria = criteria;
}

public BooleanExpression getPredicate() {

PathBuilder<FilterMatch> entityPath = new PathBuilder<>(FilterMatch.class, "FilterMatch");

if (FilterUtils.isNumeric(criteria.getValue().toString())) {

NumberPath<Double> path = entityPath.getNumber(criteria.getKey(), Double.class);
double value = Double.parseDouble(criteria.getValue().toString());

switch (criteria.getOperation()) {
case ":":
return path.eq(value);
case ">":
return path.goe(value);
case "<":
return path.loe(value);
}
} else {

StringPath path = entityPath.getString(criteria.getKey());

if (criteria.getOperation().equalsIgnoreCase(":")) {
return path.containsIgnoreCase(criteria.getValue().toString());
}
}
return null;
}
}

所以这个集成测试会抛出一个 NPE:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class JpaQueryDslIntegrationTest {

private static final Logger logger = LoggerFactory.getLogger(JpaQueryDslIntegrationTest.class);

@Autowired
private FilterMatchRepository matchRepository;

private FilterMatch match1;
private FilterMatch match2;

/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {

match1 = new FilterMatch();
match1.setDisplayName("Emma");
match1.setAge(40);
match1.setJobTitle("Banker");
match1.setCmHeight(150);

City leeds = new City();
leeds.setName("Leeds");
leeds.setLon(-1.548567);
leeds.setLat(53.801277);

match1.setCity(leeds);
match1.setMainPhoto("http://thecatapi.com/api/images/get?format=src&type=gif");
match1.setCompatScore(0.73f);
match1.setContactsExchanged(0);
match1.setFave(Constants.FALSE.getValue());
match1.setReligion("Christian");
matchRepository.save(match1);

match2 = new FilterMatch();
match2.setDisplayName("Diana");
match2.setAge(44);
match2.setJobTitle("Consultant");
match2.setCmHeight(153);

City london = new City();
london.setName("London");
london.setLat(51.509865);
london.setLon(-0.118092);

match2.setCity(london);
match2.setMainPhoto("http://thecatapi.com/api/images/get?format=src&type=gif");
match2.setCompatScore(0.50f);
match2.setContactsExchanged(0);
match2.setFave(Constants.TRUE.getValue());
match2.setReligion("Atheist");
matchRepository.save(match2);
}

@Test
public final void testMultipleMatch() {

MatchPredicatesBuilder builder = new MatchPredicatesBuilder().with("displayName", ":", "Emma");

Iterable<FilterMatch> results = matchRepository.findAll();
results = matchRepository.findAll(builder.build()); // This is the line that throws the NPE. i've tested and builder.build() isn't null
assertThat(results, Matchers.containsInAnyOrder(match1, match2));
}
}

我打印了 builder.build() 的内容,它是:

containsIc(FilterMatch.displayName,Emma)

这里的堆栈跟踪被删减了一点。 :

java.lang.NullPointerException
at java.lang.String$CaseInsensitiveComparator.compare(String.java:1192)
at java.lang.String$CaseInsensitiveComparator.compare(String.java:1186)
at java.util.TreeMap.getEntryUsingComparator(TreeMap.java:376)
at java.util.TreeMap.getEntry(TreeMap.java:345)
at java.util.TreeMap.get(TreeMap.java:278)
at org.hibernate.dialect.function.SQLFunctionRegistry.findSQLFunction(SQLFunctionRegistry.java:45)
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.findSQLFunction(SessionFactoryHelper.java:369)
at org.hibernate.hql.internal.ast.tree.IdentNode.getDataType(IdentNode.java:374)
at org.hibernate.hql.internal.ast.HqlSqlWalker.lookupProperty(HqlSqlWalker.java:654)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.addrExpr(HqlSqlBaseWalker.java:5003)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1286)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4707)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.functionCall(HqlSqlBaseWalker.java:2733)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1365)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4707)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4319)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2138)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:815)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:609)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:313)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:261)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:266)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:141)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153)
at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:553)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23)
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:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy58.createQuery(Unknown Source)
at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:101)
at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:94)
at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(AbstractJPAQuery.java:201)
at org.springframework.data.jpa.repository.support.QueryDslJpaRepository.findAll(QueryDslJpaRepository.java:105)
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:498)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:520)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:505)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

我有几个问题:

1)我的 MatchPredicatesBuilder 返回 BooleanExpression,因为我正在遵循的教程说我应该这样做,但我不知道为什么编译器不会对此感到窒息。我已经查阅了 java 文档,但它仍然是一个谜。

2) 为什么会抛出 NPE? builder.build() 不为空。从堆栈跟踪中很难看出。

最佳答案

最终的答案是,将实体表命名为类本身名称之外的任何其他名称都行不通。当您让 hibernate 自动创建数据库和架构时,就会发生这种情况。

我将 MatchPredicate 类中的行更改为:

    PathBuilder<FilterMatch> entityPath = new PathBuilder<>(FilterMatch.class, "FilterMatch");

至:

    PathBuilder<FilterMatch> entityPath = new PathBuilder<>(FilterMatch.class, "matches");

这导致了其他异常。所以现在它又回到了小写的“filtermatch”,它现在也与实体类上的表注释名称相同:

@Table(name="filtermatch")

我也改变了:

@SequenceGenerator(name = "MATCHES_SEQ_GENERATOR", sequenceName = "MATCHES_SEQ",
initialValue = 1, allocationSize = 1)

至:

@GenericGenerator(
name = "MATCH_SEQ_GENERATOR",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "MATCH_SEQ"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1")
})

它消除了启动日志中的一些已弃用的错误。

关于java - Spring Query DSL 给出空指针异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48462275/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com