0

I have a recursive method that get's flagged with a "Wrong Argument Type" error and I'm not clear why. On first entering the method, the parameters are:

checkMapping(Map<String, Object> inObjectMap, 
             In object, 
             List<DataGetter<In, Out>> inObjectDataGetters)

If recursion is needed, the recursion is:

checkMapping(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

However on the recursion I get an error for List<DataGetter<Out, ?>> objectDataGetters:

"Wrong 3rd Argument Type: found List<DataGetter<Out, ?>> objectDataGetters: required List<DataGetter<Out, Out>> objectDataGetters"

From my code I can't see what I'm doing wrong and why the wildcard isn't accepted:

private <In, Out> void checkMapping(Map<String, Object> objectMap, 
                                    In object, 
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        String key = getter.getDataName();
        Out value = getter.getData(object);

        List<DataGetter<Out, ?>> valueGetters = getter.getOutGetters();
        if(valueGetters.size() == 0) {
            //Check mapping is correct
            assertThat(objectMap.get(key), isValue(value));
        } else {
            //Recursion
            try {
                Map<String, Object> valueMap = (Map<String, Object>) objectMap.get(key);
                checkMapping(valueMap, value, valueGetters); //***Error is here***//
            } catch (ClassCastException e) {
                fail();
            }
        }
    }
}

I am writing a test to test the mapping of member variables in objects to a Map<String, Object> (to test some JSON serialisation). The String is the variable name and Object is the value which can also be a Map if the member is an object. I am using the above recursive method to check the mapping is correct. The DataGetter<In, Out> is a way to call the mapped object's getter method to compare the member variable value with that stored in the Map:

abstract class DataGetter<In, Out> {
    private String mDataName;
    private List<DataGetter<Out, ?>> mOutGetters;

    public abstract Out getData(In item);

    public DataGetter(String dataName) {
        mDataName = dataName;
        mOutGetters = new ArrayList<>();
    }

    public DataGetter(String dataName, List<DataGetter<Out, ?>> outGetters) {
        mDataName = dataName;
        mOutGetters = outGetters;
    }

    public String getDataName() {
        return mDataName;
    }

    public List<DataGetter<Out, ?>> getOutGetters() {
        return mOutGetters;
    }
}

The OutGetters are the getters for the variable returned by getData(In item) if it happens to be another object.

I hope this makes sense. What am I doing wrong?

Thanks, Riz

Edit: Solution Following on from ILya's answer below I guess it's the wild card in the list. If I change the signature to take a DataGetter (just to see what would happen), there is no error and ILya's solution works. I guess the wild card means not all elements can be guaranteed to be of the same type so that is why CheckMapping(.) doesn't accept it. Using Ilya's answer (which Ihave accepted) I have solved this by splitting the code in the loop out into CheckMappingForGetter which calls CheckMappingRecursive for the recursion:

private <In> void checkMappingRecursive(Map<String, Object> objectMap,
                                        In object,
                                        List<DataGetter<In, ?>> objectDataGetters) {
    for(DataGetter<In, ?> getter : objectDataGetters) {
        checkMappingForGetter(objectMap, object, getter);
    }
}

private <In, Out> void checkMapping(Map<String, Object> objectMap,
                                    In object,
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        checkMappingForGetter(objectMap, object, getter);
    }
}
chdryra
  • 523
  • 5
  • 17

1 Answers1

0

You are getting this error because checkMapping methods go through Type Erasure process. So in fact your root problem is this. To fix it you can rename your recursive method from

checkMapping(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

to

checkMappingRecursive(Map<String, Object> outObjectMap, 
             Out object, 
             List<DataGetter<Out, ?>> outObjectDataGetters)

and use it

private <In, Out> void checkMapping(Map<String, Object> objectMap, 
                                    In object, 
                                    List<DataGetter<In, Out>> objectDataGetters) {
    for(DataGetter<In, Out> getter : objectDataGetters) {
        String key = getter.getDataName();
        Out value = getter.getData(object);

        List<DataGetter<Out, ?>> valueGetters = getter.getOutGetters();
        if(valueGetters.size() == 0) {
            //Check mapping is correct
            assertThat(objectMap.get(key), isValue(value));
        } else {
            //Recursion
            try {
                Map<String, Object> valueMap = (Map<String, Object>) objectMap.get(key);
                checkMappingRecursive(valueMap, value, valueGetters); 
            } catch (ClassCastException e) {
                fail();
            }
        }
    }
}
Community
  • 1
  • 1
Ilya
  • 2,177
  • 15
  • 19
  • Thanks for the reply. I have tried your suggestion but it doesn't seem to fix the problem - it just moves it to the recursive method (assuming I understood your answer correctly and just wrapped CheckMapping in CheckMappingRecursive)... – chdryra May 19 '16 at 11:16
  • It seems to be something to so with outObjectGetters being a list. If I change the signature to take a DataGetter (just to see what would happen), there is no error and the above solution works. – chdryra May 19 '16 at 11:44
  • I suggested to have separate method for recursion call to distinguish it from non recursive checkMapping – Ilya May 19 '16 at 18:46