Output the difference between each field of two objects in Java
MiscUtil.java
public interface MiscUtil {
//Object before change to o1 and object after change to o2(Same class as o1)Specify
//If new, specify null for o1
default String getCompareFieldValuesString(Object o1, Object o2, List<Class<?>> skipFieldClasses, List<String> skipFieldNames) {
try {
Set<String> skipFieldNamesSet = new HashSet<>(skipFieldNames);
Class<?> clazz = o1 != null ? o1.getClass() : o2.getClass();
StringBuffer sb = new StringBuffer();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Class<?> fieldClass = field.getType();
if (isAssignable(fieldClass, skipFieldClasses)) {
continue;
}
String fieldName = field.getName();
if (skipFieldNamesSet.contains(fieldName)) {
continue;
}
Object o1Value = o1 != null ? field.get(o1) : null;
Object o2Value = field.get(o2);
if (isAssignable(fieldClass, Arrays.asList(String.class)) && isEmpty((String) o1Value) && isEmpty((String) o2Value)) {
continue; //String null and empty string are equivalent(Proposal original)
}
if (isAssignable(fieldClass, Arrays.asList(LocalDateTime.class, LocalTime.class))) {
fieldName = fieldName.replaceAll("Raw$", ""); //LocalDateTime ・ Do not output "Raw" at the end of the LocalTime field name(Proposal original)
}
String o1ValueString = getValueString(o1Value);
String o2ValueString = getValueString(o2Value);
if (!equals(o1ValueString, o2ValueString)) {
if (sb.length() > 0) {
sb.append(", ");
}
if (o1 != null) {
sb.append(String.format("%s:%s->%s", fieldName, o1ValueString, o2ValueString));
} else {
sb.append(String.format("%s:%s", fieldName, o2ValueString));
}
}
}
return sb.toString();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
default boolean isAssignable(Class<?> fromClass, List<Class<?>> toClasses) {
for (Class<?> toClass : toClasses) {
if (toClass.isAssignableFrom(fromClass)) {
return true;
}
}
return false;
}
default boolean isEmpty(String s) {
return StringUtils.isEmpty(s); //Null and empty string are treated as Empty
}
default boolean equals(Object o1, Object o2) {
if (o1 != null) {
return o1.equals(o2);
}
return false; //False even if both are null(Should it be true?)
}
default String getValueString(Object o) {
if (o == null) {
return "null";
}
if (o instanceof String) {
String s = (String) o;
return String.format("\"%s\"", escape(s));
}
if (o instanceof LocalDateTime) {
return toStr(plus9Hours((LocalDateTime) o)); //Add 9 hours(Proposal original)
}
if (o instanceof LocalTime) {
return toStr(plus9Hours((LocalTime) o)); //Add 9 hours(Proposal original)
}
if (o instanceof LocalDate) {
return toStr((LocalDate) o);
}
return String.format("%s", o.toString());
}
default String escape(String s) {
return s.replaceAll("\n", "\\\\n"); //Line breaks\\Convert to n
}
static final String DATE_FORMAT = "yyyy/MM/dd(E)";
static final String TIME_FORMAT = "HH:mm";
static final String DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT;
default String toStr(LocalDateTime datetime) {
return datetime != null ? DateTimeFormatter.ofPattern(DATETIME_FORMAT, Locale.JAPANESE).format(datetime) : null;
}
default String toStr(LocalDate date) {
return date != null ? DateTimeFormatter.ofPattern(DATE_FORMAT, Locale.JAPANESE).format(date) : null;
}
default String toStr(LocalTime time) {
return time != null ? DateTimeFormatter.ofPattern(TIME_FORMAT, Locale.JAPANESE).format(time) : null;
}
default LocalDateTime plus9Hours(LocalDateTime localDateTime) {
return localDateTime != null ? localDateTime.plusHours(9) : null;
}
default LocalTime plus9Hours(LocalTime localTime) {
return localTime != null ? localTime.plusHours(9) : null;
}
}