Spring Boot,Hibernate,Querydsl:antlr.NoViableAltException:意外令牌
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot,Hibernate,Querydsl:antlr.NoViableAltException:意外令牌相关的知识,希望对你有一定的参考价值。
我目前正在使用Spring Boot,Hibernate和querydsl开发数据仓库。几乎一切都工作正常,但是我无法对我的一个实体group
进行搜索请求。错误,并没有真正的帮助:
我的请求很简单/group/advancedSearch?page=0&size=10&sort=name,asc&search=groupCode:dfa,name:dfa,
当我调用存储库方法时,错误会在我的服务中引发。
antlr.NoViableAltException: unexpected token: group
[...]
java.lang.NullPointerException: null
为了使它更容易理解,我的代码如下。我对大多数实体都使用相同的方法,并且工作正常。因为我不知道unexpected token group
可能来自何处,所以我查看了生成的类QGroup
,在那里我发现了代码public static final QGroup group = new QGroup("group1");
的这种平静。名称group1
让我感到奇怪,但是我不确定是否与错误有关。在所有其他类中,字符串始终是带有小写字母的类的名称。
我以为实体group
可能是重复的,所以querydsl将创建group
和group1
,但事实并非如此。因此,有什么想法可能会导致错误,以及如何防止/修复错误?
实体:
@Entity
@Table(name = "[Group]")
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Group_ID")
private long groupId;
@ManyToOne()
@JoinColumn(name = "Dimension_ID")
private Dimension dimension;
@Column(name = "Dimension_ID", updatable = false, insertable = false)
private Long dimensionId;
@Column(name = "GroupCode")
private String groupCode;
@Column(name = "Name")
private String name;
[...]
}
出现错误的控制器功能:
@RequestMapping(value = GROUP_URL + "/advancedSearch", method = RequestMethod.GET)
@ResponseBody
public PagedResources<Group> advancedSearch(
@RequestParam(value = "search", required = false) String search,
Pageable pageable, @RequestParam MultiValueMap<String, String> parameters,
PersistentEntityResourceAssembler persistentEntityResourceAssembler
) {
SimpleGrantedAuthority[] allowedRoles = {SYSADMIN};
GeneralPredicateBuilder<Group> builder = new GeneralPredicateBuilder<>(Group.class);
Predicate predicate = predicateService.getPredicateFromParameters(parameters, Group.class);
Page<Group> results = service.advancedSearch(
this.buildAdvancedSearch(search, predicate, builder), pageable, allowedRoles);
return super.toPagedResource(results, persistentEntityResourceAssembler);
}
public Predicate buildAdvancedSearch(String search, Predicate predicate, GeneralPredicateBuilder<T> builder) {
if (search != null) {
Pattern pattern = Pattern.compile("(\w+?)(:|<|>)(\w+?),");
Matcher matcher = pattern.matcher(search + ",");
while (matcher.find()) {
builder.with(matcher.group(1), matcher.group(2), matcher.group(3));
}
BooleanExpression expression = builder.build();
if (predicate != null) {
predicate = expression.and(predicate);
} else {
predicate = expression;
}
}
return predicate;
}
PredicateService
:
@Service
public class PredicateService {
@Autowired
private final QuerydslPredicateBuilder querydslPredicateBuilder;
@Autowired
private final QuerydslBindingsFactory querydslBindingsFactory;
public PredicateService(QuerydslPredicateBuilder querydslPredicateBuilder, QuerydslBindingsFactory querydslBindingsFactory) {
this.querydslPredicateBuilder = querydslPredicateBuilder;
this.querydslBindingsFactory = querydslBindingsFactory;
}
public <T> Predicate getPredicateFromParameters(final MultiValueMap<String, String> parameters, Class<T> tClass) {
TypeInformation<T> typeInformation = ClassTypeInformation.from(tClass);
return querydslPredicateBuilder.getPredicate(typeInformation, parameters, querydslBindingsFactory.createBindingsFor(typeInformation));
}
}
服务方法:
public Page<Group> advancedSearch(Predicate predicate, Pageable pageable, SimpleGrantedAuthority[] roles){
if (SecurityUtils.userHasAnyRole(roles)) {
return this.repository.findAll(predicate, pageable); // <-- here the errors raise
} else throw new ForbiddenException(FORBIDDEN);
}
存储库:
@RepositoryRestResource(collectionResourceRel = GROUP_URL, path = GROUP_URL)
@CrossOrigin(exposedHeaders = "Access-Control-Allow-Origin")
public interface GroupRepository extends PagingAndSortingRepository<Group, Long>, JpaSpecificationExecutor<Group>, QuerydslPredicateExecutor<Group> {
}
由querydsl生成的类QGroup
:
@Generated("com.querydsl.codegen.EntitySerializer")
public class QGroup extends EntityPathBase<Group> {
private static final long serialVersionUID = 384278695L;
private static final PathInits INITS = PathInits.DIRECT2;
public static final QGroup group = new QGroup("group1"); // <-- this is confusing
[...]
更新:
我终于找到了生成的查询:
select group1
from Group group1
where ?1 = ?1 and lower(group.groupCode) like ?2 escape '!'
我认为这是问题所在。在SQL开发人员视图中,group.groupCode
应该为group1.groupCode
。有人知道如何解决此问题吗?
更新2 [2020-02-14]:
GeneralPredicateBuilder:
public class GeneralPredicateBuilder<T> {
private List<SearchCriteria> params;
private final Class<T> type;
public GeneralPredicateBuilder(Class<T> type) {
this.params = new ArrayList<>();
this.type = type;
}
public GeneralPredicateBuilder<T> with(String key, String operation, Object value) {
params.add(new SearchCriteria(key, operation, value));
return this;
}
public BooleanExpression build() {
if (params.size() == 0) {
return null;
}
List<BooleanExpression> predicates = params.stream().map(param -> {
GeneralPredicate<T> predicate = new GeneralPredicate<T>(param, type);
BooleanExpression tmp = predicate.getPredicate();
return tmp;
}).filter(Objects::nonNull).collect(Collectors.toList());
BooleanExpression result = Expressions.asBoolean(true).isTrue();
for (BooleanExpression predicate : predicates) {
result = result.and(predicate);
}
return result;
}
public List<Predicate> buildPredicate(){
if (params.size() == 0) {
return null;
}
return params.stream().map(param -> {
GeneralPredicate<T> predicate = new GeneralPredicate<>(param, type);
return predicate.getPredicate();
}).filter(Objects::isNull).collect(Collectors.toList());
}
}
public class GeneralPredicate<T> {
private SearchCriteria searchCriteria;
private final Class<T> type;
private final String variable;
public GeneralPredicate(SearchCriteria param, Class<T> type) {
searchCriteria = param;
this.type = type;
if(type.getSimpleName().equals("Group")){
this.variable = "group1";
} else {
this.variable = type.getSimpleName().replaceFirst("" + type.getSimpleName().charAt(0), "" + type.getSimpleName().charAt(0)).toLowerCase();
}
}
public BooleanExpression getPredicate() {
PathBuilder<T> entityPath = new PathBuilder<T>(type, variable);
if (isNumeric(searchCriteria.getValue().toString())) {
NumberPath<Integer> path = entityPath.getNumber(searchCriteria.getKey(), Integer.class);
int value = Integer.parseInt(searchCriteria.getValue().toString());
switch (searchCriteria.getOperation()) {
case ":":
return path.eq(value);
case ">":
return path.goe(value);
case "<":
return path.loe(value);
}
} else {
StringPath path = entityPath.getString(searchCriteria.getKey());
switch (searchCriteria.getOperation()) {
case ":":
return path.containsIgnoreCase(searchCriteria.getValue().toString());
case "<":
return path.startsWith(searchCriteria.getValue().toString());
case ">":
return path.endsWith(searchCriteria.getValue().toString());
}
}
return null;
}
}
您会在构造函数中找到脏修补程序。我真的很讨厌它,但是它正在运行,并且生成的sql正在运行。
也许我以错误的方式使用了通用名称。我愿意征求意见。
以上是关于Spring Boot,Hibernate,Querydsl:antlr.NoViableAltException:意外令牌的主要内容,如果未能解决你的问题,请参考以下文章
spring boot 集成 jpa+hibernate+jdbcTemplate
Spring Boot JPA Hibernate - 以毫秒精度存储日期