Skip to content

Commit

Permalink
Merge pull request #79 from sanliangitch/fix-array
Browse files Browse the repository at this point in the history
修复对象diff不支持数组
  • Loading branch information
mouzt authored Sep 1, 2022
2 parents 5f3dd21 + 66fb46f commit b4910cb
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.diff.IDiffItemsToLogContentService;
import com.mzt.logapi.util.diff.ArrayDiffer;
import de.danielbechler.diff.ObjectDifferBuilder;
import de.danielbechler.diff.comparison.ComparisonService;
import de.danielbechler.diff.node.DiffNode;
import lombok.extern.slf4j.Slf4j;

Expand Down Expand Up @@ -43,7 +45,12 @@ public String diff(Object source, Object target) {
log.error("diff的两个对象类型不同, source.class={}, target.class={}", source.getClass().toString(), target.getClass().toString());
return "";
}
DiffNode diffNode = ObjectDifferBuilder.buildDefault().compare(target, source);
ObjectDifferBuilder objectDifferBuilder = ObjectDifferBuilder.startBuilding();
DiffNode diffNode = objectDifferBuilder
.differs().register((differDispatcher, nodeQueryService) ->
new ArrayDiffer(differDispatcher, (ComparisonService) objectDifferBuilder.comparison(), objectDifferBuilder.identity()))
.build()
.compare(target, source);
return diffItemsToLogContentService.toLogContent(diffNode, source, target);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

/**
Expand Down Expand Up @@ -61,11 +62,11 @@ private void generateAllFieldLog(Object sourceObject, Object targetObject, Strin
if (StringUtils.isEmpty(filedLogName)) {
return;
}
//是否是List类型的字段
boolean valueIsCollection = valueIsCollection(node, sourceObject, targetObject);
// 是否是容器类型的字段
boolean valueIsContainer = valueIsContainer(node, sourceObject, targetObject);
//获取值的转换函数
DiffNode.State state = node.getState();
String logContent = getDiffLogContent(filedLogName, node, state, sourceObject, targetObject, diffLogFieldAnnotation.function(), valueIsCollection);
String logContent = getDiffLogContent(filedLogName, node, state, sourceObject, targetObject, diffLogFieldAnnotation.function(), valueIsContainer);
if (!StringUtils.isEmpty(logContent)) {
stringBuilder.append(logContent).append(logRecordProperties.getFieldSeparator());
}
Expand All @@ -80,15 +81,16 @@ private String getFieldLogName(DiffNode node, DiffLogField diffLogFieldAnnotatio
return filedLogName;
}

private boolean valueIsCollection(DiffNode node, Object sourceObject, Object targetObject) {
private boolean valueIsContainer(DiffNode node, Object sourceObject, Object targetObject) {
if (sourceObject != null) {
Object sourceValue = node.canonicalGet(sourceObject);
if (sourceValue == null) {
if (targetObject != null) {
return node.canonicalGet(targetObject) instanceof Collection;
return node.canonicalGet(targetObject) instanceof Collection || node.canonicalGet(targetObject).getClass().isArray();
}
} else {
return sourceValue instanceof Collection || sourceValue.getClass().isArray();
}
return sourceValue instanceof Collection;
}
return false;
}
Expand Down Expand Up @@ -137,6 +139,9 @@ public String getDiffLogContent(String filedLogName, DiffNode node, DiffNode.Sta
private Collection<Object> getListValue(DiffNode node, Object object) {
Object fieldSourceValue = getFieldValue(node, object);
//noinspection unchecked
if (fieldSourceValue != null && fieldSourceValue.getClass().isArray()) {
return new ArrayList<>(Arrays.asList((Object[]) fieldSourceValue));
}
return fieldSourceValue == null ? Lists.newArrayList() : (Collection<Object>) fieldSourceValue;
}

Expand Down
135 changes: 135 additions & 0 deletions bizlog-sdk/src/main/java/com/mzt/logapi/util/diff/ArrayDiffer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.mzt.logapi.util.diff;

import de.danielbechler.diff.access.Accessor;
import de.danielbechler.diff.access.Instances;
import de.danielbechler.diff.comparison.ComparisonStrategy;
import de.danielbechler.diff.comparison.ComparisonStrategyResolver;
import de.danielbechler.diff.differ.Differ;
import de.danielbechler.diff.differ.DifferDispatcher;
import de.danielbechler.diff.identity.IdentityStrategy;
import de.danielbechler.diff.identity.IdentityStrategyResolver;
import de.danielbechler.diff.node.DiffNode;
import de.danielbechler.util.Assert;

import java.util.*;

/**
* @author: wulang
* @date: 2022-08-27 20:26
**/
public class ArrayDiffer implements Differ {
private final DifferDispatcher differDispatcher;
private final ComparisonStrategyResolver comparisonStrategyResolver;
private final IdentityStrategyResolver identityStrategyResolver;

public ArrayDiffer(DifferDispatcher differDispatcher, ComparisonStrategyResolver comparisonStrategyResolver, IdentityStrategyResolver identityStrategyResolver) {
Assert.notNull(differDispatcher, "differDispatcher");
this.differDispatcher = differDispatcher;
Assert.notNull(comparisonStrategyResolver, "comparisonStrategyResolver");
this.comparisonStrategyResolver = comparisonStrategyResolver;
Assert.notNull(identityStrategyResolver, "identityStrategyResolver");
this.identityStrategyResolver = identityStrategyResolver;
}

@Override
public boolean accepts(final Class<?> type) {
return !type.isPrimitive() && type.isArray();
}

@Override
public final DiffNode compare(final DiffNode parentNode, final Instances collectionInstances) {
final DiffNode collectionNode = newNode(parentNode, collectionInstances);
final IdentityStrategy identityStrategy = identityStrategyResolver.resolveIdentityStrategy(collectionNode);
if (identityStrategy != null) {
collectionNode.setChildIdentityStrategy(identityStrategy);
}
if (collectionInstances.hasBeenAdded()) {
final Collection<?> addedItems = findCollection(collectionInstances.getWorking());
compareItems(collectionNode, collectionInstances, addedItems, identityStrategy);
collectionNode.setState(DiffNode.State.ADDED);
} else if (collectionInstances.hasBeenRemoved()) {
final Collection<?> removedItems = findCollection(collectionInstances.getBase());
compareItems(collectionNode, collectionInstances, removedItems, identityStrategy);
collectionNode.setState(DiffNode.State.REMOVED);
} else if (collectionInstances.areSame()) {
collectionNode.setState(DiffNode.State.UNTOUCHED);
} else {
final ComparisonStrategy comparisonStrategy = comparisonStrategyResolver.resolveComparisonStrategy(collectionNode);
if (comparisonStrategy == null) {
compareInternally(collectionNode, collectionInstances, identityStrategy);
} else {
compareUsingComparisonStrategy(collectionNode, collectionInstances, comparisonStrategy);
}
}
return collectionNode;
}

private Collection<?> findCollection(Object source) {
return source == null ? new ArrayList<>() : new LinkedList<>(Arrays.asList((Object[]) source));
}

private static DiffNode newNode(final DiffNode parentNode,
final Instances collectionInstances) {
final Accessor accessor = collectionInstances.getSourceAccessor();
final Class<?> type = collectionInstances.getType();
return new DiffNode(parentNode, accessor, type);
}

private void compareItems(final DiffNode collectionNode,
final Instances collectionInstances,
final Iterable<?> items,
final IdentityStrategy identityStrategy) {
for (final Object item : items) {
final Accessor itemAccessor = new ArrayItemAccessor(item, identityStrategy);
differDispatcher.dispatch(collectionNode, collectionInstances, itemAccessor);
}
}

private void compareInternally(final DiffNode collectionNode,
final Instances collectionInstances,
final IdentityStrategy identityStrategy) {
final Collection<?> working = Arrays.asList((Object[]) collectionInstances.getWorking());
final Collection<?> base = Arrays.asList((Object[]) collectionInstances.getBase());

final Iterable<?> added = new LinkedList<Object>(working);
final Iterable<?> removed = new LinkedList<Object>(base);
final Iterable<?> known = new LinkedList<Object>(base);

remove(added, base, identityStrategy);
remove(removed, working, identityStrategy);
remove(known, added, identityStrategy);
remove(known, removed, identityStrategy);

compareItems(collectionNode, collectionInstances, added, identityStrategy);
compareItems(collectionNode, collectionInstances, removed, identityStrategy);
compareItems(collectionNode, collectionInstances, known, identityStrategy);
}

private static void compareUsingComparisonStrategy(final DiffNode collectionNode,
final Instances collectionInstances,
final ComparisonStrategy comparisonStrategy) {
comparisonStrategy.compare(collectionNode,
collectionInstances.getType(),
collectionInstances.getWorking(Collection.class),
collectionInstances.getBase(Collection.class));
}

private void remove(final Iterable<?> from, final Iterable<?> these, final IdentityStrategy identityStrategy) {
final Iterator<?> iterator = from.iterator();
while (iterator.hasNext()) {
final Object item = iterator.next();
if (contains(these, item, identityStrategy)) {
iterator.remove();
}
}
}

private boolean contains(final Iterable<?> haystack, final Object needle, final IdentityStrategy identityStrategy) {
for (final Object item : haystack) {
if (identityStrategy.equals(needle, item)) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.mzt.logapi.util.diff;

import de.danielbechler.diff.access.Accessor;
import de.danielbechler.diff.access.TypeAwareAccessor;
import de.danielbechler.diff.identity.EqualsIdentityStrategy;
import de.danielbechler.diff.identity.IdentityStrategy;
import de.danielbechler.diff.selector.CollectionItemElementSelector;
import de.danielbechler.diff.selector.ElementSelector;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

/**
* @author: wulang
* @date: 2022-08-27 20:34
**/
public class ArrayItemAccessor implements TypeAwareAccessor, Accessor {

private final Object referenceItem;
private final IdentityStrategy identityStrategy;

/**
* Default implementation uses IdentityService.EQUALS_IDENTITY_STRATEGY.
*
* @param referenceItem
*/
public ArrayItemAccessor(final Object referenceItem) {
this(referenceItem, EqualsIdentityStrategy.getInstance());
}

/**
* Allows for custom IdentityStrategy.
*
* @param referenceItem
* @param identityStrategy
*/
public ArrayItemAccessor(final Object referenceItem,
final IdentityStrategy identityStrategy) {
Assert.notNull(identityStrategy, "identityStrategy");
this.referenceItem = referenceItem;
this.identityStrategy = identityStrategy;
}

@Override
public Class<?> getType() {
return referenceItem != null ? referenceItem.getClass() : null;
}

@Override
public String toString() {
return "collection item " + getElementSelector();
}

@Override
public ElementSelector getElementSelector() {
final CollectionItemElementSelector selector = new CollectionItemElementSelector(referenceItem);
return identityStrategy == null ? selector : selector.copyWithIdentityStrategy(identityStrategy);
}

@Override
public Object get(final Object target) {
final Collection targetCollection = objectAsCollection(target);
if (targetCollection == null) {
return null;
}
for (final Object item : targetCollection) {
if (item != null && identityStrategy.equals(item, referenceItem)) {
return item;
}
}
return null;
}

@Override
public void set(final Object target, final Object value) {
final Collection<Object> targetCollection = objectAsCollection(target);
if (targetCollection == null) {
return;
}
final Object previous = get(target);
if (previous != null) {
unset(target);
}
targetCollection.add(value);
}

@SuppressWarnings("unchecked")
private static Collection<Object> objectAsCollection(final Object object) {
if (object == null) {
return null;
} else if (object.getClass().isArray()) {
return new ArrayList<>(Arrays.asList((Object[]) object));
}
throw new IllegalArgumentException(object.getClass().toString());
}

@Override
public void unset(final Object target) {
final Collection<?> targetCollection = objectAsCollection(target);
if (targetCollection == null) {
return;
}
final Iterator<?> iterator = targetCollection.iterator();
while (iterator.hasNext()) {
final Object item = iterator.next();
if (item != null && identityStrategy.equals(item, referenceItem)) {
iterator.remove();
break;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.mzt.logserver.function;

import com.mzt.logapi.service.IParseFunction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
* @author: wulang
* @date: 2022-08-27 21:01
**/
@Slf4j
@Component
public class ExtInfoParseFunction implements IParseFunction {
@Override
public boolean executeBefore() {
return false;
}

@Override
public String functionName() {
return "extInfo";
}

@Override
public String apply(Object value) {
log.info("===========");
if (StringUtils.isEmpty(value)) {
return "";
}
log.info("当前拓展信息值为,{}", value);
return value.toString();
}
}
3 changes: 3 additions & 0 deletions bizlog-server/src/main/java/com/mzt/logserver/pojo/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public class Order {
@DiffLogField(name = "列表项", function = "ORDER")
private List<String> items;

@DiffLogField(name = "拓展信息", function = "extInfo")
private String[] extInfo;

@Data
public static class UserDO {
@DiffLogField(name = "用户ID")
Expand Down
Loading

0 comments on commit b4910cb

Please sign in to comment.