private DifferDispatcher newDifferDispatcher(final DifferProvider differProvider) { return new DifferDispatcher( differProvider, circularReferenceService, circularReferenceService, inclusionService, returnableNodeService, introspectionService, categoryService); }
private Differ newBeanDiffer(final DifferDispatcher differDispatcher) { return new BeanDiffer( differDispatcher, introspectionService, returnableNodeService, comparisonService, introspectionService); }
public void pushAll(final Iterable<Differ> differs) { for (final Differ differ : differs) { push(differ); } }
/** * Recursively inspects the given objects and returns a node representing their differences. Both objects * have be have the same type. * * @param working This object will be treated as the successor of the `base` object. * @param base This object will be treated as the predecessor of the <code>working</code> object. * @return A node representing the differences between the given objects. */ public <T> DiffNode compare(final T working, final T base) { dispatcher.resetInstanceMemory(); try { return dispatcher.dispatch(DiffNode.ROOT, Instances.of(working, base), RootAccessor.getInstance()); } finally { dispatcher.clearInstanceMemory(); } } }
public ObjectDiffer build() { final DifferProvider differProvider = new DifferProvider(); final DifferDispatcher differDispatcher = newDifferDispatcher(differProvider); differProvider.push(newBeanDiffer(differDispatcher)); differProvider.push(newCollectionDiffer(differDispatcher)); differProvider.push(newMapDiffer(differDispatcher)); differProvider.push(newPrimitiveDiffer()); differProvider.pushAll(createCustomDiffers(differDispatcher)); return new ObjectDiffer(differDispatcher); }
private Iterable<Differ> createCustomDiffers(final DifferDispatcher differDispatcher) { final Collection<DifferFactory> differFactories = differService.getDifferFactories(); final Collection<Differ> differs = new ArrayList<Differ>(differFactories.size()); for (final DifferFactory differFactory : differFactories) { differs.add(differFactory.createDiffer(differDispatcher, nodeQueryService)); } return differs; } }
private DiffNode compare(final DiffNode parentNode, final Instances instances) { final Differ differ = differProvider.retrieveDifferForType(instances.getType()); if (differ == null) { throw new IllegalStateException("Couldn't create Differ for type '" + instances.getType() + "'. This mustn't happen, as there should always be a fallback differ."); } return differ.compare(parentNode, instances); }
private void compareInternally(final DiffNode collectionNode, final Instances collectionInstances, final IdentityStrategy identityStrategy) { final Collection<?> working = collectionInstances.getWorking(Collection.class); final Collection<?> base = collectionInstances.getBase(Collection.class); 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); }
protected static void rememberInstances(final DiffNode parentNode, final Instances instances) { final NodePath nodePath = getNodePath(parentNode, instances); logger.debug("[ {} ] Remembering --- WORKING: {} <=> BASE: {}", nodePath, instances.getWorking(), instances.getBase()); transactionalPushToCircularReferenceDetectors(nodePath, instances); }
private static Iterable<?> findKnownKeys(final Instances instances) { final Set<?> keys = instances.getWorking(Map.class).keySet(); final Collection<?> changed = Collections.setOf(keys); changed.removeAll(findAddedKeys(instances)); changed.removeAll(findRemovedKeys(instances)); return changed; }
private void compareEntries(final DiffNode mapNode, final Instances mapInstances, final Iterable<?> keys) { for (final Object key : keys) { differDispatcher.dispatch(mapNode, mapInstances, new MapEntryAccessor(key)); } } }
private static DiffNode findNodeMatchingPropertyPath(final DiffNode node, final NodePath nodePath) { if (node == null) { return null; } if (node.matches(nodePath)) { return node; } return findNodeMatchingPropertyPath(node.getParentNode(), nodePath); }
private Differ newPrimitiveDiffer() { return new PrimitiveDiffer(comparisonService); }
private Differ newCollectionDiffer(final DifferDispatcher differDispatcher) { return new CollectionDiffer(differDispatcher, comparisonService, identityService); }
private Differ newMapDiffer(final DifferDispatcher differDispatcher) { return new MapDiffer(differDispatcher, comparisonService); }
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(); } } }
public Differ retrieveDifferForType(final Class<?> type) { if (type == null) { throw new IllegalArgumentException("Missing 'type'"); } for (final Differ differ : differs) { if (differ.accepts(type)) { return differ; } } throw new IllegalStateException("Couldn't find a differ for type: " + type.getName()); } }
public DifferDispatcher(final DifferProvider differProvider, final CircularReferenceDetectorFactory circularReferenceDetectorFactory, final CircularReferenceExceptionHandler circularReferenceExceptionHandler, final IsIgnoredResolver ignoredResolver, final IsReturnableResolver returnableResolver, final PropertyAccessExceptionHandlerResolver propertyAccessExceptionHandlerResolver, final CategoryResolver categoryResolver) { Assert.notNull(differProvider, "differFactory"); this.differProvider = differProvider; Assert.notNull(ignoredResolver, "ignoredResolver"); this.isIgnoredResolver = ignoredResolver; Assert.notNull(categoryResolver, "categoryResolver"); this.categoryResolver = categoryResolver; this.circularReferenceDetectorFactory = circularReferenceDetectorFactory; this.circularReferenceExceptionHandler = circularReferenceExceptionHandler; this.isReturnableResolver = returnableResolver; this.propertyAccessExceptionHandlerResolver = propertyAccessExceptionHandlerResolver; resetInstanceMemory(); }
private void compareItems(final DiffNode collectionNode, final Instances collectionInstances, final Iterable<?> items, final IdentityStrategy identityStrategy) { for (final Object item : items) { final Accessor itemAccessor = new CollectionItemAccessor(item, identityStrategy); differDispatcher.dispatch(collectionNode, collectionInstances, itemAccessor); } }
private static DiffNode newCircularNode(final DiffNode parentNode, final Instances instances, final NodePath circleStartPath) { final DiffNode node = new DiffNode(parentNode, instances.getSourceAccessor(), instances.getType()); node.setState(DiffNode.State.CIRCULAR); node.setCircleStartPath(circleStartPath); node.setCircleStartNode(findNodeMatchingPropertyPath(parentNode, circleStartPath)); return node; } }