Skip to content

Commit

Permalink
✨ Add diff function annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
lzhpo committed Apr 25, 2024
1 parent 621b5f8 commit e730fa7
Show file tree
Hide file tree
Showing 15 changed files with 431 additions and 319 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/lzhpo/logger/annotation/Logger.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
* @author lzhpo
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Logger {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lzhpo.logger.diff;
package com.lzhpo.logger.annotation;

import com.lzhpo.logger.domain.OrderResponse;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.annotation.*;

/**
* @author lzhpo
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DiffNestedOrderResponse {
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggerDiffField {

private List<OrderResponse> orderResponses;
/**
* Disable this field to diff.
*
* @return whether disable
*/
boolean disabled() default false;
}
34 changes: 34 additions & 0 deletions src/main/java/com/lzhpo/logger/annotation/LoggerDiffObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright lzhpo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lzhpo.logger.annotation;

import java.lang.annotation.*;

/**
* @author lzhpo
*/
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggerDiffObject {

/**
* Disable this object to diff.
*
* @return whether disable
*/
boolean disabled() default false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
* @author lzhpo
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggerFunction {

/**
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/lzhpo/logger/diff/DiffObjectResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@
package com.lzhpo.logger.diff;

import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author lzhpo
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DiffObjectResult {

private String oldObjectName;
Expand Down
184 changes: 136 additions & 48 deletions src/main/java/com/lzhpo/logger/diff/LoggerDiffFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.lzhpo.logger.LoggerConstant;
import com.lzhpo.logger.LoggerDiffProperties;
import com.lzhpo.logger.annotation.LoggerComponent;
import com.lzhpo.logger.annotation.LoggerDiffField;
import com.lzhpo.logger.annotation.LoggerDiffObject;
import com.lzhpo.logger.annotation.LoggerFunction;
import com.lzhpo.logger.context.LoggerContextHolder;
import java.lang.reflect.Field;
Expand Down Expand Up @@ -56,88 +58,174 @@ public class LoggerDiffFunction implements InitializingBean {
*
* @param oldObject the old object
* @param newObject the new object
* @return the diff results
* @return the formated diff message
*/
@LoggerFunction(LoggerConstant.FUNCTION_DIFF)
public static String diff(Object oldObject, Object newObject) {
log.debug("DIFF oldObject={}, newObject={}", oldObject, newObject);
StringJoiner messageJoiner = new StringJoiner(DIFF_MESSAGE_DELIMITER);
if (Objects.isNull(oldObject) || Objects.isNull(newObject)) {
return messageJoiner.toString();
return StrUtil.EMPTY;
}

if (isDisabledObjectDiff(oldObject, newObject)) {
log.debug("The oldObject or newObject has been disabled diff.");
return StrUtil.EMPTY;
}

final DiffObjectResult diffObjectResult;
if (isSimpleValueType(oldObject, newObject)) {
diffObjectResult = getDiffSimpleResult(oldObject, newObject);
} else {
diffObjectResult = getDiffObjectResult(oldObject, newObject);
}

LoggerContextHolder.putDiffResult(diffObjectResult);
return formatDiffResultsMessage(diffObjectResult.getFieldResults());
}

/**
* Get diff object result.
*
* @param oldObject the old object
* @param newObject the new object
* @return the diff result
*/
public static DiffObjectResult getDiffObjectResult(Object oldObject, Object newObject) {
Class<?> oldObjectClass = oldObject.getClass();
Class<?> newObjectClass = newObject.getClass();

final DiffObjectResult diffObjectResult = new DiffObjectResult();
final List<DiffFieldResult> diffFieldResults = new ArrayList<>();
diffObjectResult.setFieldResults(diffFieldResults);
diffObjectResult.setOldObjectName(oldObjectClass.getName());
diffObjectResult.setNewObjectName(newObjectClass.getName());
DiffObjectResult diffObjectResult = createDiffObjectResult(oldObjectClass.getName(), newObjectClass.getName());
List<DiffFieldResult> diffFieldResults = diffObjectResult.getFieldResults();

if (ClassUtil.isSimpleValueType(oldObjectClass) || ClassUtil.isSimpleValueType(newObjectClass)) {
log.debug("The oldObject or newObject is simple value type.");
if (!Objects.equals(oldObject, newObject)) {
diffFieldResults.add(createDiffResult(null, oldObject, newObject));
}
} else {
Map<String, Field> oldFieldMap = getFieldsMap(oldObjectClass);
Map<String, Field> newFieldMap = getFieldsMap(newObjectClass);

oldFieldMap.forEach((oldFieldName, oldField) -> {
Object oldObjFieldValue = ReflectUtil.getFieldValue(oldObject, oldFieldName);
Field newField = newFieldMap.get(oldFieldName);

if (Objects.nonNull(newField)) {
Object newValue = ReflectUtil.getFieldValue(newObject, oldFieldName);
if (!Objects.equals(oldObjFieldValue, newValue)) {
diffFieldResults.add(createDiffResult(oldFieldName, oldObjFieldValue, newValue));
log.debug("Field {} updated from [{}] to [{}]", oldFieldName, oldObjFieldValue, newValue);
}
} else {
diffFieldResults.add(createDiffResult(oldFieldName, oldObjFieldValue, null));
log.debug("Field {}={} has bean deleted.", oldFieldName, oldObjFieldValue);
}
});
Map<String, Field> oldFieldMap = getFieldsMap(oldObjectClass);
Map<String, Field> newFieldMap = getFieldsMap(newObjectClass);

newFieldMap.forEach((newFieldName, newField) -> {
if (!oldFieldMap.containsKey(newFieldName)) {
Object newValue = ReflectUtil.getFieldValue(newObject, newFieldName);
diffFieldResults.add(createDiffResult(newFieldName, null, newValue));
log.debug("Field {}={} has bean added.", newFieldName, newValue);
oldFieldMap.forEach((oldFieldName, oldField) -> {
Object oldObjFieldValue = ReflectUtil.getFieldValue(oldObject, oldFieldName);
Field newField = newFieldMap.get(oldFieldName);

if (Objects.nonNull(newField)) {
Object newValue = ReflectUtil.getFieldValue(newObject, oldFieldName);
if (!Objects.equals(oldObjFieldValue, newValue)) {
diffFieldResults.add(createDiffResult(oldFieldName, oldObjFieldValue, newValue));
log.debug("Field {} updated from [{}] to [{}]", oldFieldName, oldObjFieldValue, newValue);
}
});
} else {
diffFieldResults.add(createDiffResult(oldFieldName, oldObjFieldValue, null));
log.debug("Field {}={} has bean deleted.", oldFieldName, oldObjFieldValue);
}
});

newFieldMap.forEach((newFieldName, newField) -> {
if (!oldFieldMap.containsKey(newFieldName)) {
Object newValue = ReflectUtil.getFieldValue(newObject, newFieldName);
diffFieldResults.add(createDiffResult(newFieldName, null, newValue));
log.debug("Field {}={} has bean added.", newFieldName, newValue);
}
});

return diffObjectResult;
}

/**
* Get diff simple value type result.
*
* @param oldObject the old object
* @param newObject the new object
* @return the diff result
*/
public static DiffObjectResult getDiffSimpleResult(Object oldObject, Object newObject) {
Class<?> oldObjectClass = oldObject.getClass();
Class<?> newObjectClass = newObject.getClass();
DiffObjectResult diffObjectResult = createDiffObjectResult(oldObjectClass.getName(), newObjectClass.getName());
if (!Objects.equals(oldObject, newObject)) {
diffObjectResult.getFieldResults().add(createDiffResult(null, oldObject, newObject));
}
return diffObjectResult;
}

/**
* Format diff message by configured template.
*
* @param diffFieldResults the diff field results
* @return the formated diff message
*/
public static String formatDiffResultsMessage(List<DiffFieldResult> diffFieldResults) {
StringJoiner messageJoiner = new StringJoiner(DIFF_MESSAGE_DELIMITER);
diffFieldResults.forEach(diffResult -> {
Map<String, Object> messageTemplateMap = createMessageTemplateMap(diffResult);
messageJoiner.add(StrUtil.format(DIFF_MESSAGE_TEMPLATE, messageTemplateMap, false));
});

LoggerContextHolder.putDiffResult(diffObjectResult);
return messageJoiner.toString();
}

/**
* Whether the old object or new object is disabled diff.
*
* @param oldObject the old object
* @param newObject the new object
* @return the result of whether disabled diff object
*/
public static boolean isDisabledObjectDiff(Object oldObject, Object newObject) {
return Optional.of(oldObject.getClass())
.map(clazz -> clazz.getAnnotation(LoggerDiffObject.class))
.map(LoggerDiffObject::disabled)
.isPresent()
|| Optional.of(newObject.getClass())
.map(clazz -> clazz.getAnnotation(LoggerDiffObject.class))
.map(LoggerDiffObject::disabled)
.isPresent();
}

/**
* Get object class all fields and convert to map.
*
* @param objectClass the object class
* @return fields map
* @return the fields map
*/
private static Map<String, Field> getFieldsMap(Class<?> objectClass) {
public static Map<String, Field> getFieldsMap(Class<?> objectClass) {
return Arrays.stream(ReflectUtil.getFields(objectClass))
.filter(field -> !Optional.ofNullable(field.getAnnotation(LoggerDiffField.class))
.map(LoggerDiffField::disabled)
.isPresent())
.collect(Collectors.toMap(Field::getName, Function.identity()));
}

/**
* Whether is simple value type.
*
* @param oldObject the old object
* @param newObject the new object
* @return the result of whether is simple value type
*/
public static boolean isSimpleValueType(Object oldObject, Object newObject) {
return ClassUtil.isSimpleValueType(oldObject.getClass()) || ClassUtil.isSimpleValueType(newObject.getClass());
}

/**
* Create diff object result.
*
* @param oldObjectClassName the old object class name
* @param newObjectClassName the new object class name
* @return the diff object result
*/
public static DiffObjectResult createDiffObjectResult(String oldObjectClassName, String newObjectClassName) {
DiffObjectResult diffObjectResult = new DiffObjectResult();
diffObjectResult.setOldObjectName(oldObjectClassName);
diffObjectResult.setNewObjectName(newObjectClassName);
diffObjectResult.setFieldResults(new ArrayList<>());
return diffObjectResult;
}

/**
* Create diff result.
*
* @param oldFieldName the old object field name
* @param oldValue the old object field value
* @param newValue the new object field value
* @return diff result
* @param oldValue the old object field value
* @param newValue the new object field value
* @return the diff field result
*/
private static DiffFieldResult createDiffResult(String oldFieldName, Object oldValue, Object newValue) {
public static DiffFieldResult createDiffResult(String oldFieldName, Object oldValue, Object newValue) {
DiffFieldResult diffResult = new DiffFieldResult();
diffResult.setFieldName(oldFieldName);
diffResult.setOldValue(oldValue);
Expand All @@ -149,9 +237,9 @@ private static DiffFieldResult createDiffResult(String oldFieldName, Object oldV
* Create diff format message template map.
*
* @param diffResult the diff result
* @return message template map
* @return the message template map
*/
private static Map<String, Object> createMessageTemplateMap(DiffFieldResult diffResult) {
public static Map<String, Object> createMessageTemplateMap(DiffFieldResult diffResult) {
Map<String, Object> messageTemplateMap = new HashMap<>();
messageTemplateMap.put(DIFF_MESSAGE_TEMPLATE_FILED_NAME, diffResult.getFieldName());
messageTemplateMap.put(DIFF_MESSAGE_TEMPLATE_OLD_FIELD_VALUE, diffResult.getOldValue());
Expand Down
Loading

0 comments on commit e730fa7

Please sign in to comment.