The error reported indicates that you are trying converting the String
OnboardingTaskStatus.2769df0841
to a OnboardingTaskStatus
enumeration value which is not defined.
Please, don't look for workarounds on how to deal with the wrong value, try to find out why you got the wrong value in the first place instead. Test your Specification
in isolation, with correct enum values, and see if it works. If it does - I think it will probably do - review the code you are using to provide values for the OnboardingTaskSearchParams
form, and double check the value of the status
parameter, perhaps you are iterating over the enumeration in a wrong way, etc. Probably not, but be sure as well that your status
column doesn't contain incorrect values - inserted manually, in a previous version of the code...
In addition, to mitigate the problem, I would try to directly define your enum in the search criteria, Spring will handle the conversion between the String
and the enum value automatically.
I mean, instead of defining status
as String
in OnboardingTaskSearchParams
, just define the field as an enum:
@Getter
@Setter
public class OnboardingTaskSearchParams {
private String title;
private OnboardingTaskStatus status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
Or maybe better:
@Getter
@Setter
public class OnboardingTaskSearchParams {
private String title;
private List<OnboardingTaskStatus> statuses;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
And use the enum as such in your Specification
:
public Page<OnboardingTaskDto> findOnboardingTasks(OnboardingTaskSearchParams params, Pageable pageable){
Specification<OnboardingTasks> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getStatus() != null) {
predicates.add(cb.equal(root.get("status"), params.getStatus()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return onboardingTasksService.findAll(spec, pageable).map(onboardingMapper::taskToTaskDTO);
}
Or, if you use multiple values as search criteria:
public Page<OnboardingTaskDto> findOnboardingTasks(OnboardingTaskSearchParams params, Pageable pageable){
Specification<OnboardingTasks> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
final List<OnboardingTaskStatus> statuses = params.getStatuses();
if (statuses != null && ! statuses.isEmpty()){
predicates.add(root.get("status").in(statuses));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return onboardingTasksService.findAll(spec, pageable).map(onboardingMapper::taskToTaskDTO);
}
You must be sure that in your frontend you provide the right values in your form for the possible OnboardingTaskStatus
enum ones, NEW
, IN_PROGRESS
, and DISABLED
.
It is important to note that Spring will immediately complaint at the Web layer if your form is submitted and if it finds any incorrect enumeration value before reaching your service or database related code.
If you actually need to check if the enumeration value exists and still use String
for representing status
in your search criteria, you have multiple options.
You can for example use the method isValidEnum
in the EnumUtils
class from the commons-lang library:
if(EnumUtils.isValidEnum(OnboardingTaskStatus.class, params.getStatus())){
predicates.add(
cb.equal(
root.get("status"),
OnboardingTaskStatus.valueOf(params.getStatus())
)
);
}
You can use the getIfPresent
method from Guava's Enums
class:
Optional<OnboardingTaskStatus> optStatus = Enums.getIfPresent(OnboardingTaskStatus.class, params.getStatus());
if(optStatus.isPresent()){
predicates.add(
cb.equal(
root.get("status"),
OnboardingTaskStatus.valueOf(optStatus.get())
)
);
}
This other SO question provides several alternatives from Jon Skeet and others.
With Java 8, you have several options as well. In addition to the ones provided in other answers, you can try for example:
Optional<OnboardingTaskStatus> optStatus = EnumSet.allOf(OnboardingTaskStatus.class)
.stream()
.filter(e -> e.name().equals(params.getStatus()))
.findAny();
if(optStatus.isPresent()){
predicates.add(
cb.equal(
root.get("status"),
OnboardingTaskStatus.valueOf(optStatus.get())
)
);
}
Finally, it seems that you are using some kind of conversion mechanism under the hood for converting the status
String
to the corresponding enum value in your Specification
; on the contrary, as you can check in the Hibernate source code, this line will raise a different error:
predicates.add(cb.equal(root.get("status"), params.getStatus()));
Something like:
Parameter value ... did not match expected type ...
If that is the case, please, review that logic as well, perhaps the problem is there.