SQiShER/java-object-diff

Couldn't find a differ for type: [Ljava.lang.String;

docfirefly opened this issue · 10 comments

How can I handle following error message:

Caused by: java.lang.IllegalStateException: Couldn't find a differ for type: [Ljava.lang.String;

Thanks

You are trying to diff an array of strings. Arrays are currently not supported out-of-the-box. Sorry about that.

However, you have a couple of options:

  1. The easy, but most invasive way: use either a List or Set instead of an Array.
  2. The not so easy, but most flexible way: implement a custom Differ that's capable of handling string arrays or arrays in general. Since you only need to consider your own use case, it could be a pretty simple implementation. Small caveat: I've yet to try to write such a differ without being able to make changes to the core. So you may or may not hit some obstacles, which require a little work on the core.
  3. You could also try to create a wrapper object that's optimized for diffing and does the same as 1.) but in a non-invasive way.

Bonus option: if you don't care about the problematic property, you can simply instruct the object differ to ignore it.

This is related to #120

Ok thank you for your fast reply.
I guess I cannot use option 1 and 3 because there are too many classes involved and I am not the owner of them. The easiest way would be to ignore them but I am not sure if they are important (the project is in planning stage at the moment).
And I ve already thought about option 2 and tried it but as you mentionend it wasnt so easy for me ;)

Do you have any idea when version 0.93 or even better 1.0 will be released?

I currently don't have much spare time at my hands, so I can't make any promises. Although I do want to eventually add proper array-support, I can't tell you when I'll get to it. But if you can name a few of the things keeping you from implementing your own differ, I may be able to make some quick changes to get those issues out of the way.

Ok, so far I haven't started to implement my own differ. The project planning state isn't completed atm. If I need furthter help I will contact you - Thanks!

Closing this for now. Feel free to reopen if anything new comes up.

You can try with my little trick :)

public class ArrayDiffer implements Differ {

    private static final Logger LOG = LoggerFactory.getLogger(ArrayDiffer.class);

    private final CollectionDiffer collectionDiffer;

    public ArrayDiffer(DifferDispatcher differDispatcher, ObjectDifferBuilder objectDifferBuilder) {
        collectionDiffer = new CollectionDiffer(differDispatcher, (ComparisonService) objectDifferBuilder.comparison(), objectDifferBuilder.identity());
    }

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

    @Override
    public DiffNode compare(DiffNode parentNode, Instances instances) {

        final Object[] workings = (Object[]) instances.getWorking();
        final Object[] bases = (Object[]) instances.getBase();

        Instances instances1 = Instances.of(instances.getSourceAccessor(),
                Arrays.asList(workings),
                Arrays.asList(bases),
                instances.getFresh());

        return collectionDiffer.compare(parentNode, instances1);
    }
}

@manhvvhtth
How to integrate your code into my own project?
I am comparing two objects which has String arrays like this

working.foo[0].bar

working and foo is object and bar is String array

To @songtianyi ,

First, you need to add addition differ like below:

public ObjectDiffer createObjectDifferHelper() {

        final ObjectDifferBuilder objectDifferBuilder = ObjectDifferBuilder.startBuilding();

        ObjectDiffer objectDiffer = objectDifferBuilder
                .differs().register((differDispatcher, nodeQueryService) -> new ByteArrayDiffer())
                .differs().register((differDispatcher, nodeQueryService) -> new ArrayDiffer(differDispatcher, objectDifferBuilder))
                .build();


        return objectDiffer;
    }

// herin I also created ByteArrayDiffer

import de.danielbechler.diff.access.Instances;
import de.danielbechler.diff.differ.Differ;
import de.danielbechler.diff.node.DiffNode;

public final class ByteArrayDiffer implements Differ {

    @Override
    public boolean accepts(Class<?> aClass) {
        return byte[].class.equals(aClass);
    }

    @Override
    public DiffNode compare(DiffNode diffNode, Instances instances) {
        final DiffNode beanNode = new DiffNode(diffNode, instances.getSourceAccessor(), instances.getType());

        if (instances.areNull() || instances.areSame())
            beanNode.setState(DiffNode.State.UNTOUCHED);
        else if (instances.hasBeenAdded())
            beanNode.setState(DiffNode.State.ADDED);
        else if (instances.hasBeenRemoved())
            beanNode.setState(DiffNode.State.REMOVED);
        else
            beanNode.setState(DiffNode.State.CHANGED);

        return beanNode;
    }
}

Then you can use your object differ normally:

final ObjectDiffer objectDiffer = createObjectDifferHelper();

DiffNode diffNode = objectDiffer.compare(newRevisionEntity, oldRevisionEntity);

Hope this response is not late :),

To @songtianyi ,

First, you need to add addition differ like below:

public ObjectDiffer createObjectDifferHelper() {

        final ObjectDifferBuilder objectDifferBuilder = ObjectDifferBuilder.startBuilding();

        ObjectDiffer objectDiffer = objectDifferBuilder
                .differs().register((differDispatcher, nodeQueryService) -> new ByteArrayDiffer())
                .differs().register((differDispatcher, nodeQueryService) -> new ArrayDiffer(differDispatcher, objectDifferBuilder))
                .build();


        return objectDiffer;
    }

// herin I also created ByteArrayDiffer

import de.danielbechler.diff.access.Instances;
import de.danielbechler.diff.differ.Differ;
import de.danielbechler.diff.node.DiffNode;

public final class ByteArrayDiffer implements Differ {

    @Override
    public boolean accepts(Class<?> aClass) {
        return byte[].class.equals(aClass);
    }

    @Override
    public DiffNode compare(DiffNode diffNode, Instances instances) {
        final DiffNode beanNode = new DiffNode(diffNode, instances.getSourceAccessor(), instances.getType());

        if (instances.areNull() || instances.areSame())
            beanNode.setState(DiffNode.State.UNTOUCHED);
        else if (instances.hasBeenAdded())
            beanNode.setState(DiffNode.State.ADDED);
        else if (instances.hasBeenRemoved())
            beanNode.setState(DiffNode.State.REMOVED);
        else
            beanNode.setState(DiffNode.State.CHANGED);

        return beanNode;
    }
}

Then you can use your object differ normally:

final ObjectDiffer objectDiffer = createObjectDifferHelper();

DiffNode diffNode = objectDiffer.compare(newRevisionEntity, oldRevisionEntity);

Hope this response is not late :),

I used the method you provided but still reported an error:
java.lang.IllegalArgumentException: class [Ljava.lang.String;