Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复对象diff不支持数组 #79

Merged
merged 1 commit into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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