java.lang.IllegalArgumentException:没有枚举 BusinessCustomersStatus.4d29e059cf
java.lang.IllegalArgumentException: No enum BusinessCustomersStatus.4d29e059cf
我想使用 ENUM 值创建搜索规范:
搜索枚举:
public enum BusinessCustomersStatus {
A("active"),
O("onboarding"),
N("not_verified"),
V("verified"),
S("suspended"),
I("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
}
搜索 DTO:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<BusinessCustomersStatus> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
搜索规范:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable)
{
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
Optional<BusinessCustomersStatus> optStatus = EnumSet.allOf(BusinessCustomersStatus.class)
.stream()
.filter(e -> e.name().equals(params.getStatus()))
.findAny();
if(optStatus.isPresent()){
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
predicates.add(root.get("status").in(statuses));
}
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
实体:
@Entity
@Table(name = "business_customers")
public class BusinessCustomers implements Serializable {
..........
@Enumerated(EnumType.STRING)
@Column(name = "status", length = 20)
private BusinessCustomersStatus status;
......
}
但是我得到这个错误:
java.lang.IllegalArgumentException: No enum constant org.service.businesscustomers.BusinessCustomersStatus.4d29e059cf] with root cause
java.lang.IllegalArgumentException: No enum constant org.service.businesscustomers.BusinessCustomersStatus.4d29e059cf
at java.base/java.lang.Enum.valueOf(Enum.java:273)
你知道我该如何解决这个问题吗?
POC 示例:https://github.com/rcbandit111/Search_specification_POC
我认为您混合了我对您 original question 的回答中公开的几个选项。
假设您将 status
定义为 List
,如您提供的示例所示:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<BusinessCustomersStatus> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
您可以尝试在 Specification
中使用 in
子句:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
// According to your comments, please, see this example
// about how to wrap the List returned from your form
final List<BusinessCustomersStatus> statuses = Optional.ofNullable(params.getStatus()).orElse(Collections.emptyList());
if (statuses != null && !statuses.isEmpty()){
predicates.add(root.get("status").in(statuses));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
或者您可以遍历 status
集合以验证每个值并构建具有所需过滤条件的 or
谓词:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
List<Predicate> statusPredicates = new ArrayList<Predicate>();
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
statuses.forEach(status -> {
Optional<BusinessCustomersStatus> optStatus = businessCustomersStatusEnumSet
.stream()
.filter(e -> e.equals(status))
.findAny();
if(optStatus.isPresent()){
statusPredicates.add(cb.equal(root.get("status"), cb.literal(status)));
}
});
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
事实上,由于您已经在使用枚举而不是 String
s 我认为前面代码中出现的 forEach
循环可以简化如下:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
List<Predicate> statusPredicates = new ArrayList<Predicate>();
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
statuses.forEach(status -> {
if(businessCustomersStatusEnumSet.contains(status)){
statusPredicates.add(cb.equal(root.get("status"), cb.literal(status)));
}
});
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
甚至,采用不同的方法:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
List<Predicate> statusPredicates = businessCustomersStatusEnumSet.stream()
.filter(status -> statuses.contains(status))
.map(status -> cb.equal(root.get("status"), cb.literal(status)))
.collect(Collectors.toList())
;
if (statusPredicates != null && !statusPredicates.isEmpty()) {
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
提供的第一种方法应该在典型用例中使用,虽然最后一种可能可以通过删除不正确的值来解决问题,但实际问题仍然存在:为什么您收到不正确的值枚举值排在第一位?请检查您的数据库记录以寻找不正确的记录,并确保 - 抱歉这么说,但有时它会发生,我面对自己 - 你在任何地方都使用注释值,例如 A
,而不是关联的值有了它,active
,继续这个例子;它们是应该存储在数据库中的值,由您的前端提交的值,等等。
如果您需要或更喜欢使用与您的枚举关联的 status
文字,您可以遵循以下方法。
首先,修改你的枚举并在转换过程中提供一个辅助方法:
public enum BusinessCustomersStatus {
ACTIVE("active"),
ONBOARDING("onboarding"),
NOT_VERIFIED("not_verified"),
VERIFIED("verified"),
SUSPENDED("suspended"),
INACTIVE("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
public static BusinessCustomersStatus fromStatus(String status) {
switch (status) {
case "active": {
return ACTIVE;
}
case "onboarding": {
return ONBOARDING;
}
case "not_verified": {
return NOT_VERIFIED;
}
case "verified": {
return VERIFIED;
}
case "suspended": {
return SUSPENDED;
}
case "inactive": {
return INACTIVE;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
然后,修改 BusinessCustomersSearchParams
以使用 String
而不是 status
字段的枚举:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<String> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
最后,修改您的规范以处理转换过程。例如:
@Override
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable)
{
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("description")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<String> statuses = Optional.ofNullable(params.getStatus()).orElse(Collections.emptyList());
if (statuses != null && !statuses.isEmpty()){
List<BusinessCustomersStatus> statusesAsEnum = statuses.stream()
.map(status -> BusinessCustomersStatus.fromStatus(status))
.collect(Collectors.toList())
;
predicates.add(root.get("status").in(statusesAsEnum));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
在插入过程中也可以使用fromStatus
方法
话虽如此,我不知道它是否是您所需要的,但我认为您可以在这里使用 AttributeConverter
。考虑例如:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class BusinessCustomersStatusAttributeConverter
implements AttributeConverter<BusinessCustomersStatus, String> {
public String convertToDatabaseColumn( BusinessCustomersStatus value ) {
if ( value == null ) {
return null;
}
return value.getStatus();
}
public BusinessCustomersStatus convertToEntityAttribute( String value ) {
if ( value == null ) {
return null;
}
return BusinessCustomersStatus.fromStatus( value );
}
}
您需要在枚举中提供额外的 getStatus
方法:
package org.merchant.database.service.businesscustomers;
public enum BusinessCustomersStatus {
ACTIVE("active"),
ONBOARDING("onboarding"),
NOT_VERIFIED("not_verified"),
VERIFIED("verified"),
SUSPENDED("suspended"),
INACTIVE("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
public String getStatus() {
return status;
}
public static BusinessCustomersStatus fromStatus(String status) {
switch (status) {
case "active": {
return ACTIVE;
}
case "onboarding": {
return ONBOARDING;
}
case "not_verified": {
return NOT_VERIFIED;
}
case "verified": {
return VERIFIED;
}
case "suspended": {
return SUSPENDED;
}
case "inactive": {
return INACTIVE;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
现在,您的 BusinessCustomers
实体应修改为:
@Entity
@Table(name = "business_customers")
public class BusinessCustomers implements Serializable {
..........
@Convert( converter = BusinessCustomersStatusAttributeConverter.class )
private BusinessCustomersStatus status;
......
}
请注意,如果您在数据库中实施 AttributeConverter
方法,存储的值也将是与枚举关联的文字 status
,而不是枚举 name
本身。如果您更喜欢存储枚举值,请在 BusinessCustomers
中保留 @Enumerated
方法。如果您使用 AttributeConverter
方法进行测试,请记住将 status
列的值更新为与枚举对应的值。
最后,关于您最后的评论,您收到了 "status": "ACTIVE"
:这是因为您的 Mapstruct Mapper
提供了枚举的 name
作为 status
BusinessCustomersFullDTO
中的字段。要处理适当的转换,请尝试以下操作:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.merchant.config.BaseMapperConfig;
import org.merchant.database.entity.BusinessCustomers;
import org.merchant.database.service.businesscustomers.BusinessCustomersStatus;
import org.merchant.dto.businesscustomers.BusinessCustomersFullDTO;
@Mapper(config = BaseMapperConfig.class)
public interface BusinessCustomersMapper {
@Mapping(source = "status", target = "status", qualifiedByName = "businessCustomersToDTOStatus")
BusinessCustomersFullDTO toFullDTO(BusinessCustomers businessCustomers);
@Named("busineessCustomersToDTOStatus")
public static String businessCustomersToDTOStatus(final BusinessCustomersStatus status) {
if (status == null) {
return null;
}
return status.getStatus();
}
}
在代码中,我们使用 @Named
和 qualifiedByName
来提供自定义转换。请参阅 relevant documentation.
你应该用常量值定义 enum
,那么这些值就不会是 instanceof
的东西(也许由于其他原因它不喜欢枚举,但它仍然读取 no enum constant
).
public static final int STATUS_ACTIVE = 0;
public static final int STATUS_ONBOARDING = 1;
public static final int STATUS_NOT_VERIFIED = 2;
public static final int STATUS_VERIFIED = 3;
public static final int STATUS_SUSPENDED = 4;
public static final int STATUS_INACTIVE = 5;
public enum BusinessCustomersStatus {
STATUS_ACTIVE,
STATUS_ONBOARDING,
STATUS_NOT_VERIFIED,
STATUS_VERIFIED,
STATUS_SUSPENDED,
STATUS_INACTIVE
}
然后 @Enumerated
应该是 EnumType.ORDINAL
:
@Enumerated(EnumType.ORDINAL)
@Column(name = "status")
我想使用 ENUM 值创建搜索规范:
搜索枚举:
public enum BusinessCustomersStatus {
A("active"),
O("onboarding"),
N("not_verified"),
V("verified"),
S("suspended"),
I("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
}
搜索 DTO:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<BusinessCustomersStatus> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
搜索规范:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable)
{
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
Optional<BusinessCustomersStatus> optStatus = EnumSet.allOf(BusinessCustomersStatus.class)
.stream()
.filter(e -> e.name().equals(params.getStatus()))
.findAny();
if(optStatus.isPresent()){
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
predicates.add(root.get("status").in(statuses));
}
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
实体:
@Entity
@Table(name = "business_customers")
public class BusinessCustomers implements Serializable {
..........
@Enumerated(EnumType.STRING)
@Column(name = "status", length = 20)
private BusinessCustomersStatus status;
......
}
但是我得到这个错误:
java.lang.IllegalArgumentException: No enum constant org.service.businesscustomers.BusinessCustomersStatus.4d29e059cf] with root cause
java.lang.IllegalArgumentException: No enum constant org.service.businesscustomers.BusinessCustomersStatus.4d29e059cf
at java.base/java.lang.Enum.valueOf(Enum.java:273)
你知道我该如何解决这个问题吗?
POC 示例:https://github.com/rcbandit111/Search_specification_POC
我认为您混合了我对您 original question 的回答中公开的几个选项。
假设您将 status
定义为 List
,如您提供的示例所示:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<BusinessCustomersStatus> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
您可以尝试在 Specification
中使用 in
子句:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
// According to your comments, please, see this example
// about how to wrap the List returned from your form
final List<BusinessCustomersStatus> statuses = Optional.ofNullable(params.getStatus()).orElse(Collections.emptyList());
if (statuses != null && !statuses.isEmpty()){
predicates.add(root.get("status").in(statuses));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
或者您可以遍历 status
集合以验证每个值并构建具有所需过滤条件的 or
谓词:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
List<Predicate> statusPredicates = new ArrayList<Predicate>();
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
statuses.forEach(status -> {
Optional<BusinessCustomersStatus> optStatus = businessCustomersStatusEnumSet
.stream()
.filter(e -> e.equals(status))
.findAny();
if(optStatus.isPresent()){
statusPredicates.add(cb.equal(root.get("status"), cb.literal(status)));
}
});
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
事实上,由于您已经在使用枚举而不是 String
s 我认为前面代码中出现的 forEach
循环可以简化如下:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
List<Predicate> statusPredicates = new ArrayList<Predicate>();
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
statuses.forEach(status -> {
if(businessCustomersStatusEnumSet.contains(status)){
statusPredicates.add(cb.equal(root.get("status"), cb.literal(status)));
}
});
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
甚至,采用不同的方法:
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable) {
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<BusinessCustomersStatus> statuses = params.getStatus();
if (statuses != null && !statuses.isEmpty()){
EnumSet<BusinessCustomersStatus> businessCustomersStatusEnumSet = EnumSet.allOf(BusinessCustomersStatus.class);
List<Predicate> statusPredicates = businessCustomersStatusEnumSet.stream()
.filter(status -> statuses.contains(status))
.map(status -> cb.equal(root.get("status"), cb.literal(status)))
.collect(Collectors.toList())
;
if (statusPredicates != null && !statusPredicates.isEmpty()) {
predicates.add(
cb.or(statusPredicates.toArray(new Predicate[statusPredicates.size()]))
);
}
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
提供的第一种方法应该在典型用例中使用,虽然最后一种可能可以通过删除不正确的值来解决问题,但实际问题仍然存在:为什么您收到不正确的值枚举值排在第一位?请检查您的数据库记录以寻找不正确的记录,并确保 - 抱歉这么说,但有时它会发生,我面对自己 - 你在任何地方都使用注释值,例如 A
,而不是关联的值有了它,active
,继续这个例子;它们是应该存储在数据库中的值,由您的前端提交的值,等等。
如果您需要或更喜欢使用与您的枚举关联的 status
文字,您可以遵循以下方法。
首先,修改你的枚举并在转换过程中提供一个辅助方法:
public enum BusinessCustomersStatus {
ACTIVE("active"),
ONBOARDING("onboarding"),
NOT_VERIFIED("not_verified"),
VERIFIED("verified"),
SUSPENDED("suspended"),
INACTIVE("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
public static BusinessCustomersStatus fromStatus(String status) {
switch (status) {
case "active": {
return ACTIVE;
}
case "onboarding": {
return ONBOARDING;
}
case "not_verified": {
return NOT_VERIFIED;
}
case "verified": {
return VERIFIED;
}
case "suspended": {
return SUSPENDED;
}
case "inactive": {
return INACTIVE;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
然后,修改 BusinessCustomersSearchParams
以使用 String
而不是 status
字段的枚举:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<String> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
最后,修改您的规范以处理转换过程。例如:
@Override
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable)
{
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("description")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<String> statuses = Optional.ofNullable(params.getStatus()).orElse(Collections.emptyList());
if (statuses != null && !statuses.isEmpty()){
List<BusinessCustomersStatus> statusesAsEnum = statuses.stream()
.map(status -> BusinessCustomersStatus.fromStatus(status))
.collect(Collectors.toList())
;
predicates.add(root.get("status").in(statusesAsEnum));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
在插入过程中也可以使用fromStatus
方法
话虽如此,我不知道它是否是您所需要的,但我认为您可以在这里使用 AttributeConverter
。考虑例如:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class BusinessCustomersStatusAttributeConverter
implements AttributeConverter<BusinessCustomersStatus, String> {
public String convertToDatabaseColumn( BusinessCustomersStatus value ) {
if ( value == null ) {
return null;
}
return value.getStatus();
}
public BusinessCustomersStatus convertToEntityAttribute( String value ) {
if ( value == null ) {
return null;
}
return BusinessCustomersStatus.fromStatus( value );
}
}
您需要在枚举中提供额外的 getStatus
方法:
package org.merchant.database.service.businesscustomers;
public enum BusinessCustomersStatus {
ACTIVE("active"),
ONBOARDING("onboarding"),
NOT_VERIFIED("not_verified"),
VERIFIED("verified"),
SUSPENDED("suspended"),
INACTIVE("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
public String getStatus() {
return status;
}
public static BusinessCustomersStatus fromStatus(String status) {
switch (status) {
case "active": {
return ACTIVE;
}
case "onboarding": {
return ONBOARDING;
}
case "not_verified": {
return NOT_VERIFIED;
}
case "verified": {
return VERIFIED;
}
case "suspended": {
return SUSPENDED;
}
case "inactive": {
return INACTIVE;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
现在,您的 BusinessCustomers
实体应修改为:
@Entity
@Table(name = "business_customers")
public class BusinessCustomers implements Serializable {
..........
@Convert( converter = BusinessCustomersStatusAttributeConverter.class )
private BusinessCustomersStatus status;
......
}
请注意,如果您在数据库中实施 AttributeConverter
方法,存储的值也将是与枚举关联的文字 status
,而不是枚举 name
本身。如果您更喜欢存储枚举值,请在 BusinessCustomers
中保留 @Enumerated
方法。如果您使用 AttributeConverter
方法进行测试,请记住将 status
列的值更新为与枚举对应的值。
最后,关于您最后的评论,您收到了 "status": "ACTIVE"
:这是因为您的 Mapstruct Mapper
提供了枚举的 name
作为 status
BusinessCustomersFullDTO
中的字段。要处理适当的转换,请尝试以下操作:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.merchant.config.BaseMapperConfig;
import org.merchant.database.entity.BusinessCustomers;
import org.merchant.database.service.businesscustomers.BusinessCustomersStatus;
import org.merchant.dto.businesscustomers.BusinessCustomersFullDTO;
@Mapper(config = BaseMapperConfig.class)
public interface BusinessCustomersMapper {
@Mapping(source = "status", target = "status", qualifiedByName = "businessCustomersToDTOStatus")
BusinessCustomersFullDTO toFullDTO(BusinessCustomers businessCustomers);
@Named("busineessCustomersToDTOStatus")
public static String businessCustomersToDTOStatus(final BusinessCustomersStatus status) {
if (status == null) {
return null;
}
return status.getStatus();
}
}
在代码中,我们使用 @Named
和 qualifiedByName
来提供自定义转换。请参阅 relevant documentation.
你应该用常量值定义 enum
,那么这些值就不会是 instanceof
的东西(也许由于其他原因它不喜欢枚举,但它仍然读取 no enum constant
).
public static final int STATUS_ACTIVE = 0;
public static final int STATUS_ONBOARDING = 1;
public static final int STATUS_NOT_VERIFIED = 2;
public static final int STATUS_VERIFIED = 3;
public static final int STATUS_SUSPENDED = 4;
public static final int STATUS_INACTIVE = 5;
public enum BusinessCustomersStatus {
STATUS_ACTIVE,
STATUS_ONBOARDING,
STATUS_NOT_VERIFIED,
STATUS_VERIFIED,
STATUS_SUSPENDED,
STATUS_INACTIVE
}
然后 @Enumerated
应该是 EnumType.ORDINAL
:
@Enumerated(EnumType.ORDINAL)
@Column(name = "status")