I want to allow to sort by every field in the class, without having to write switch/ if statements. My idea was to find the Field that matches given string value by name and then, with Stream API neatly sort. IntelliJ screamed that i need to surround it with try-catch, so it is not so neatly looking, but that's not important, as it does not work.
private List<MyEntity> getSorted(List<MyEntity> list, SearchCriteria criteria) {
Field sortByField = findFieldInListByName(getFieldList(MyEntity.class), criteria.getSortBy());
return list.stream().sorted(Comparator.comparing(entity-> {
try {
return (MyEntity) sortByField.get(entity);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return entity;
})).collect(Collectors.toList());
}
In the MyEntity class I have added Comparable interface, but I am not sure what should be in the body of Compare(), as I dont want to specify how to compare objects, because it will change based on the selected sorting.
EDIT: Added Entity below:
@Data
@Entity
@Table(name = "role_management", schema = "mdr")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class MyEntity implements Comparable{
@Id
@Column(name = "uuid", unique = true, insertable = false, updatable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID uuid;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private UserEntity user;
@Basic
@NonNull
@Column(name = "role")
private String role;
@Basic
@Column(name = "action")
@Enumerated(EnumType.STRING)
private RoleAction action;
@Basic
@Column(name = "goal")
@Enumerated(EnumType.STRING)
private RoleGoal goal;
@Column(name = "date")
private LocalDateTime date;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "reporter_id", referencedColumnName = "uuid")
private UserEntity reporter;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "authorizer_id", referencedColumnName = "uuid")
private UserEntity authorizer;
@Basic
@Column(name = "ezd")
private String ezd;
@Basic
@Column(name = "is_last")
private boolean isMostRecent;
@Override
public int compareTo(Object o) {
return 0;
}
}
EDIT 2: My code based on the @Sweeper solution:
UserEntity (nullable)
@Override
public int compareTo(UserEntity other) {
if (other == null) {
return 1;
}
return this.getMail().compareTo(other.getMail());
}
Comparator:
public static Comparator getSortComparator(Field sortByField) {
return Comparator.nullsLast(Comparator.comparing(entity -> {
try {
Object fieldValue = sortByField.get(entity);
if (!(fieldValue instanceof Comparable<?>) && fieldValue != null) {
throw new IllegalArgumentException("...");
}
return (Comparable) fieldValue;
} catch (IllegalAccessException e) {
throw new MdrCommonException(e.getLocalizedMessage());
}
}));
}