В настоящее время я занимаюсь разработкой хранилища данных с использованием весенней загрузки, гибернации и 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> {
}
Сгенерированный класс QGroup
by querydsl:
@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());
}
}