InvalidDataAccessApiUsageException: значение параметра [...] не соответствует ожидаемому типу [java .util.UUID (н / д)] - PullRequest
1 голос
/ 10 марта 2020

Я использую Criteria API для создания именованных запросов с использованием фильтров. Он работает при обычном сравнении строк, но при фильтрации по UUID выдает следующую ошибку:

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [67279329-5096-4196-9E73-748B33122CE2] did not match expected type [java.util.UUID (n/a)]

Есть несколько вопросов, касающихся этой проблемы, но ни один из них не сработал, я попробовал следующее:

  • добавление @Column(name = "id", updatable = false, nullable = false) к полю сущности
  • добавление @Type(type="org.hibernate.type.UUIDCharType") к полю сущности
  • добавление @Type(type="uuid-char") к полю сущности

Foo entity:

@Entity
//lombok stuff
public class Foo {

    @Id
    private UUID id;
    private String name;
    //...
}

SQL Вариант:

CREATE TABLE foo
(
    id                    UUID    NOT NULL PRIMARY KEY,
    name                  VARCHAR NOT NULL,
    ...
);

FooController:

@GetMapping(value = "/foo")
public ResponseEntity<List<Foo>> findFoos(@RequestParam Map<String, String> filterArguments) {
    FooFilter filter = filterMapper.map(filterArguments);
    FooSpecification spec = new FooSpecification(filter);

    List<Foo> foos = fooRepo.findAll(spec);
    //...
}

FooSpecification:

public class FooSpecification extends SpecificationHelper implements Specification<Foo> {
    private final FooFilter filter;

    public FooSpecification(FooFilter filter) {
        this.filter = filter;
    }

    @Override
    public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        Predicate predicate = null;

        predicate = createIdPredicate(root, filter, criteriaBuilder, predicate);
        predicate = createNamePredicate(root, filter, criteriaBuilder, predicate);
        // ...

        return predicate;
    }

    private Predicate createIdPredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
        Predicate returnPredicate = predicate;
        if (StringUtils.isNotBlank(filter.getId()))
            returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("id")), "%" + filter.getId().toUpperCase() + "%"));
        return returnPredicate;
    }

    private Predicate createNamePredicate(Root<Foo> foo, FooFilter filter, CriteriaBuilder cb, Predicate predicate) {
        Predicate returnPredicate = predicate;
        if (StringUtils.isNotBlank(filter.getName()))
            returnPredicate = addAndPredicate(cb, predicate, cb.like(cb.upper(foo.get("name")), "%" + filter.getName().toUpperCase() + "%"));
        return returnPredicate;
    }
}

addAndPredicate - это простой вспомогательный метод, который просто использует critBuilder.and (предикат, newPredicate)

FooFilter имеет только строковые поля

Ответы [ 2 ]

1 голос
/ 11 марта 2020

Проблема в том, что ваш FooFilter содержит только String поля, и вы пытаетесь сравнить String id с UUID объектом в createIdPredicate(). И именно поэтому исключение брошено. Есть 2 решения:

  • Либо, вы должны заменить filter.getId().toUpperCase() деталь в createIdPredicate() на UUID.fromString(filter.getId()), как предложено @ tentacle
  • Или, поменяйте фильтр FooFilter так что id будет иметь тип java.util.UUID.

Кстати, ИМХО, сравнение UUIDs с like не очень хорошая идея, потому что один UUID никогда не сможет быть похожим на другой UUID, каждый объект UUID уникален. Ваш предикат должен проверить равенство идентификаторов, переданных FooFilter, и идентификатора из DB.

0 голосов
/ 11 марта 2020

Я исправил проблему, используя приведение типов, предоставляемое Criteria API.

До:

addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id")), ...));

После:

addAndPredicate(..., ..., cb.like(cb.upper(foo.get("id").as(String.class)), ...));

От: https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/Expression.html#as (java .lang.Class)

<X> Expression<X> as(java.lang.Class<X> type)

Выполнить приведение типа к выражению, возвращая новый объект выражения. Этот метод не вызывает преобразование типов: тип среды выполнения не изменяется. Предупреждение: может привести к сбою во время выполнения.

...