It always complains with:
The method add(Matrix<T>) in the type List<Matrix<T>> is not applicable for the arguments (Matrix<String>)
In the line of the Extractor class:
matrixList.add(new Matrix<String>(attributes));
It seems there is a problem in defining my generics in these 3 classes. Is there an easy way to fix that? Tried different ways and can't figure it out.
public class Test {
public static void main(String[] args) {
Extractor<String> extractor = new Extractor<>();
extractor.extract();
}
}
class Extractor<T> {
private List<Matrix<T>> matrixList;
public Extractor() {
this.matrixList = new ArrayList<>();
}
public void extract() {
List<Attribute<String>> attributes = new ArrayList<>();
attributes.add(new Attribute<String>("Test 1"));
attributes.add(new Attribute<String>("Test 2"));
// !!!! The compiler is complaining here!
matrixList.add(new Matrix<String>(attributes));
}
public List<Matrix<T>> getList() {
return matrixList;
}
}
class Matrix<T> {
private List<Attribute<T>> attributes;
public Matrix(List<Attribute<T>> attributes) {
this.attributes = attributes;
}
public List<Attribute<T>> getAttributes() {
return attributes;
}
}
class Attribute<T> {
private T attribute;
public Attribute(T attr) {
attribute = attr;
}
public T getAttr() {
return attribute;
}
}
Your code simply does not make sense. You are making Extractor etc generic, which means you want it to work for different types.
However, in Extractor.extract() method, you are specifically creating a Matrix of String and put it into your List<Matrix<T>> matrixList.
If your code only works for String, then you shouldn't make it generic. Just make List<Matrix<String>> matrixList.
Give it a thought: if now you are creating a Extractor<Integer> intExtractor, and calling intExtractor.extract(), how can it be reasonable for your code to work?
Or, to further polish your design, make it:
interface Extractor<T> {
public List<Matrix<T>> extract();
}
class DummyStringMatrixExtractor implements Extractor<String> {
// useless now, can be put in extract()
private List<Matrix<T>> matrixList;
public Extractor() {
this.matrixList = new ArrayList<>();
}
#Override
public List<Matrix<String>> extract() {
List<Attribute<String>> attributes = new ArrayList<>();
attributes.add(new Attribute<String>("Test 1"));
attributes.add(new Attribute<String>("Test 2"));
matrixList.add(new Matrix<String>(attributes));
return matrixList;
}
// useless now
public List<Matrix<T>> getList() {
return matrixList;
}
}
You can't put Matrix<String> to list of Matrix<T> (T may be any type here). If the Extractor works only with Matrix of type String, remove the type argument from there and set matrixList type to List<Matrix<String>>.
A simple solution is to use matrixList.add((Matrix<T>) new Matrix<String>(attributes)); instead.
The code imposes a very common casting problem of generics.
The approach presented in the code matrixList.add(new Matrix<String>(attributes)) implies that you want to add a Matrix element to container matrixList which is defined to contain generic template type.
You may find simpler illustrations of such hurdles in the documentation over here
Related
This is an odd question. I don't think there's a solution, but I thought I'd ask anyway.
Say I have an enum:
public enum Key {
RED(String.class),
GREEN(Integer.class),
BLUE(Short.class);
private Class<?> expectedType;
Key(Class<?> expectedType) { this.expectedType = expectedType; }
public Class<?> getExpectedType() { return expectedType; }
}
I want to use the 'expectedType' field from the Key enum as the return type of a method. See:
public class Cache {
private static Map<Key, Object> cache = new HashMap<>();
public void put(Key key, Object value) {
// Easy to validate that 'value' is of type key.getExpectedType()...
}
public <T> T get(Key key) {
Object value = cache.get(key);
// TODO need to define <T> as key.getExpectedType(). How?
}
}
See that TODO? I'd like for get() to define the return type of the 'expectedType' defined by the key parameter. E.g. if the key parameter were RED, the get() method would return a String and you could write:
String s = cache.get(Key.RED);
Is there a way to do that?
I'm thinking there isn't, but I'd love to hear of a clever solution.
Enums don't support generics, but you could use a regular class as a generic pseudo-enum:
public class Key<T> {
public static final Key<String> RED = new Key<>(String.class);
public static final Key<Integer> GREEN = new Key<>(Integer.class);
public static final Key<Short> BLUE = new Key<>(Short.class);
private final Class<T> expectedType;
private Key(Class<T> expectedType) { this.expectedType = expectedType; }
public Class<T> getExpectedType() { return expectedType; }
}
public class Cache {
private Map<Key<?>, Object> cache = new HashMap<>();
public <T> void put(Key<T> key, T value) {
cache.put(key, key.getExpectedType().cast(value));
}
public <T> T get(Key<T> key) {
return key.getExpectedType().cast(cache.get(key));
}
}
shmosel's answer is almost certainly sufficient for what you need; however, it has the slight limitation that you can't store/retrieve a generic type, because you can't get a class literal for a generic type.
Instead, you can use something like Guava's TypeCapture:
abstract class GenericKey<T> {
Type getExpectedType() {
return ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
which is a bit of reflective grossness that you shouldn't spend too much time looking at.
Notice that it's abstract, so you have to instantiate like:
new GenericKey<Integer>() {}
This is creating an anonymous subclass of GenericKey, which is part of the magic that makes it work with generic types.
Then, it's basically the same:
public class Cache {
private Map<GenericKey<?>, Object> cache = new HashMap<>();
public <T> void put(GenericKey<T> key, T value) {
cache.put(key.getExpectedType(), value);
}
public <T> T get(GenericKey<T> key) {
return (T) cache.get(key.getExpectedType());
}
}
Now you could have a GenericKey<List<Integer>>, using new new GenericKey<List<Integer>() {}, if you should so desire.
The downside of this approach is that you lose the ability to do checking on the value on the way in/out of the cache, so you could get heap pollution if you are careless with raw types.
I have a problem with Java's Generic System.
In my program is a wrapper for lists, that should have a method to return it's inner list:
public class Wrapper<T, S extends List<T>> {
private S list;
public Wrapper(S list) {
this.list = list;
}
public S get() {
return list;
}
}
Then there is a Context that holds a Map with different Wrappers and a method that returns the list of the wrapper associated with the id:
public class Context {
private Map<String, Wrapper> map;
public Wrappers() {
map.put("a", new Wrapper(ArrayList<String>());
map.put("b", new Wrapper(LinkedList<Integer>());
}
public <T, S extends List<T>> S getList(String id) {
return map.get(id).get();
}
}
Now when I call getList() I want to have a compiler warning or at least a way to realise an error before a ClassCastException gets thrown.
public class Receiver {
public doSomething() {
Context c = new Context();
c.createWrappers();
// Ok
ArrayList<String> list1 = c.getList("a");
LinkedList<Integer> list2 = c.getList("b");
// Compiler error or some way do check in getList().
ArrayList<Integer> list3 = c.getList("a");
LinkedList<String> list4 = c.getList("b");
}
}
I've actually tried a lot of things like changing the Wrapper definition to:
public class Wrapper<T, S extends List>
But when I want to implement the get() function I run into a problem I can either define the function like this:
public List<T> get() {
return list;
}
or like this
public S get() {
return list;
}
In the first example it would still be possible to do this.
public doSomething() {
//...
LinkedList<String> list = c.getList("a");
}
and in the second example it would be possible to do this.
public doSomething() {
//...
ArrayList<Integer> list = c.getList("a");
}
Is there any way to define the get method in a way like this?
public S<T> get() {
return list;
}
It seems to me like there is no way to check both the type of the list and the type of the elements at the same time.
The compiler has no way of knowing what return type is associated with the particular string you passed (strings cannot be made type-safe).
However, you could replace strings with type-safe marker objects:
class ListId<T> {
public ListId(string name) { ... }
public static final ListId<ArrayList<String>> A = new ListId<>("a");
public static final ListId<LinkedList<Integer>> B = new ListId<>("b");
}
public T getList<T>(ListId<T> id)
I have a problem when trying to match an array that is passed as a parameter to a method that receives a varargs array.
The anyVararg() matcher that is mentioned in other questions/answers doesn't work for me because I want to make sure the provided array is the one I need.
I reduced the problem to this example which is easier to understand and abstracts the problem (my real issue is production code and has busines logic so it would be confusing for the purpose of this question):
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
private Object[] objectArray;
private List<Object> expected;
private TestTarget target;
#Before
public void setUp() {
objectArray = new Object[]{ new Object() };
expected = Arrays.asList(new Object(), new Object());
target = Mockito.spy(new TestTarget());
}
#Test
public void testMakeList() { // this pass as eq works well with normal array
doReturn(expected).when(target).toList(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList(objectArray));
}
#Test
public void testMakeList1() { // this one fails as eq is not working with varargs
doReturn(expected).when(target).toList1(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
#Test
public void testMakeListWithAryEq() { // fails, aryEq is not working with varargs
doReturn(expected).when(target).toList1(AdditionalMatchers.aryEq(objectArray));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
private class TestTarget {
public List<Object> makeList(Object[] objects) {
return toList(objects);
}
public List<Object> makeList1(Object[] objects) {
return toList1(objects);
}
protected List<Object> toList(Object[] objs) {
return null; // Not implemented "Intentionally"
}
protected List<Object> toList1(Object... objs) {
return null; // Not implemented "Intentionally"
}
}
}
When I run the test cases in the class, the first test case will pass but not the other two, neither using eq nor using aryEq. Showing the following trace:
java.lang.AssertionError: expected:<[java.lang.Object#56d5e457, java.lang.Object#7482384a]> but was:<null>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:743)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
...
This happens because the eq matcher is not working with varargs arrays, is there any alternative to the eq matcher for this use case?
Ok, I think the answer here requires a custom built matcher, which can be implemented in your unit test as so:
private class MyVarargMatcher extends ArgumentMatcher<Object[]> implements VarargMatcher {
private Object[] expectedValues;
MyVarargMatcher(Object... expectedValues) {
this.expectedValues = expectedValues;
}
#Override
public boolean matches(Object varargArgument) {
return new EqualsBuilder()
.append(expectedValues, varargArgument)
.isEquals();
}
}
Then, in testMakeList1() change the first line to this:
Mockito.doReturn(expected).when(target).toList1(Mockito.argThat(new MyVarargMatcher(objectArray)));
Sources:
How to properly match varargs in Mockito
http://maciejmadej.blogspot.com/2011/11/capturing-varargs-argument-using-custom.html
This is no problem with matching varargs. The only limitation is that you have to specify each individual array entry as a matched argument. I have updated your code below to show what I mean. I created a second objectArray2 to make the point clearer. All tests pass:
#RunWith(MockitoJUnitRunner.class)
public class UnitTest {
private Object[] objectArray;
private Object[] objectArray2;
private List<Object> expected;
private TestTarget target;
private Object obj,obj2;
#Before
public void setUp() {
obj = new Object();
obj2 = new Object();
objectArray = new Object[]{ obj };
objectArray2 = new Object[]{ obj, obj2 };
expected = Arrays.asList(new Object(), new Object());
target = Mockito.spy(new TestTarget());
}
#Test
public void testMakeList() { // this pass as eq works well with normal array
doReturn(expected).when(target).toList(Mockito.eq(objectArray));
Assert.assertEquals(expected, target.makeList(objectArray));
}
#Test
public void testMakeList1() { // since objectArray has one entry you need to add one matching argument
doReturn(expected).when(target).toList1(Mockito.eq(obj));
Assert.assertEquals(expected, target.makeList1(objectArray));
}
#Test
public void testMakeListWithAryEq() { // since objectArray2 has two entries you need to add two matching arguments
doReturn(expected).when(target).toList1(Mockito.eq(obj),Mockito.eq(obj2));
Assert.assertEquals(expected, target.makeList1(objectArray2));
}
private class TestTarget {
public List<Object> makeList(Object[] objects) {
return toList(objects);
}
public List<Object> makeList1(Object[] objects) {
return toList1(objects);
}
protected List<Object> toList(Object[] objs) {
return null; // Not implemented "Intentionally"
}
protected List<Object> toList1(Object... objs) {
return null; // Not implemented "Intentionally"
}
}
}
I have to do some catching of type at runtime. I couldn't figure out how to do this.
Tricky place is that this type is generic.
Code snippet:
public class Ship<T> {
private ArrayList<T> passangers = new ArrayList<T>();
public Ship(ArrayList<T> passangers) {
this.passangers = passangers;
}
public void addPassanger(T object) {
passangers.add(object);
}
// ... rest of class
}
How to catch which type is into method addPassanger(T object) at runtime.
Catch this type of T.
Update:
I follow dasblinkenlight suggestions.
And added into main():
Ship<Droid> victoria = new Ship<Droid>(new ArrayList<Droid>(), Droid.class);
victoria.addPassanger(new Droid("Christofor Columb"));
victoria.addPassanger(new Droid("Fernando Magelan"));
victoria.addPassanger(new Droid("James Kuk"));
System.out.print("Passengers type is:");
victoria.getPassengerType();
System.out.println();
victoria.showPassangers();
But output is next:
Passengers type is:
At the sheep are presented:
1 Christofor Columb
2 Fernando Magelan
3 James Kuk
Here line:
victoria.getPassengerType();
which should return class type return nothing.
Any suggestions?
Because of type erasure, by run-time the type information is gone. The common trick here is to store the Class of T in the constructor, like this:
public class Ship<T> {
private final Class<T> passengerType;
private ArrayList<T> passengers = new ArrayList<T>();
public Sheep(ArrayList<T> passengers, Class<T> passengerType) {
this.passengers = passengers;
this.passengerType = passengerType;
}
public void addPassenger(T object) {
passengers.add(object);
}
// ... rest of class
}
I have a list of pojo's List<Pojo> pojoList; and pojo.getColour(); returns an Enum instance.
And I want to do this :
List<Pojo> newlist = new ArrayList<Pojo>();
for(Pojo pojo:pojoList){
if(pojo.getColour() == Colour.Red){
newList.add(pojo);
}
}
I could see myself using a similar function for lists of other types so rather than repeating a lot of code is their a way to make it generic and/or functional ? So that I could create sublists of different types based upon a different rule ?
First of all, I should note that if you just want a new ArrayList containing the matching elements, the way you did it in your example is just fine. Until Java has lambda expressions, you're not going to get it simpler or better looking than that.
Since you tagged this with guava, here's how you could do this with Guava. You're basically filtering the original list on the composition of a predicate (== Color.Red) and a function (pojo.getColour()). So if you had a static final Function<Pojo, Colour> called COLOUR on Pojo (like this):
public static final Function<Pojo, Colour> COLOUR =
new Function<Pojo, Colour>() {
#Override public Colour apply(Pojo input) {
return input.getColour();
}
};
you could create that combination like this:
Predicate<Pojo> isRedPojo = Predicates.compose(
Predicates.equalTo(Colour.Red), Pojo.COLOUR);
You can then create a filtered view of the original list:
Iterable<Pojo> redPojos = Iterables.filter(pojoList, isRedPojo);
And you could copy that filtered view into an ArrayList if you want:
List<Pojo> copy = Lists.newArrayList(redPojos);
You'd have to make your type implement a common interface for the check:
public interface Candidate {
public boolean isAddable();
}
The loop then would look like this
List<Candidate> newlist = new ArrayList<Candidate>();
for(Candidate pojo:pojoList){
if(pojo.isAddable()){
newList.add(pojo);
}
}
and the Pojo class would have to implement the interface:
public class Pojo implments Candidate {
// ...
#Override
public boolean isAddable() {
return isRed();
}
}
Depending on how often you use it / how many different filters (only red, only green etc.) you are using, it could make sense to create a Filter interface - if it is only to check isRed then it is probably too much code and you are better off with a simple static method.
The good thing about this design is you can use it with any objects that you want to filter (see example with String below).
public static void main(String[] args) {
List<Pojo> originalList = Arrays.asList(new Pojo(true), new Pojo(false), new Pojo(false));
List<Pojo> filteredList = Utils.getFilteredList(originalList, new Filter<Pojo>() {
#Override
public boolean match(Pojo candidate) {
return candidate.isRed();
}
});
System.out.println(originalList.size()); //3
System.out.println(filteredList.size()); //1
//Now with strings
List<String> originalStringList = Arrays.asList("abc", "abd", "def");
List<String> filteredStringList = Utils.getFilteredList(originalStringList, new Filter<String>() {
#Override
public boolean match(String candidate) {
return candidate.contains("a");
}
});
System.out.println(originalStringList.size()); //3
System.out.println(filteredStringList.size()); //2
}
public static class Utils {
public static <T> List<T> getFilteredList(List<T> list, Filter<T> filter) {
List<T> selected = new ArrayList<>();
for (T t : list) {
if (filter.match(t)) {
selected.add(t);
}
}
return selected;
}
}
public static class Pojo {
private boolean isRed;
public Pojo(boolean isRed) {
this.isRed = isRed;
}
public boolean isRed() {
return isRed;
}
}
public interface Filter<T> {
/**
* When passed a candidate object, match returns true if it matches the filter conditions,
* or false if it does not.
* #param candidate the item checked against the filter
* #return true if the item matches the filter criteria
*/
boolean match(T candidate);
}
make an generic filter interface
public interface Filter<T>{
public boolean match(T item);
}
make a method using the filter
public <T> List<T> getFilteredList(List<T> oldList, List<T> filter){
List<T> newlist = new ArrayList<T>();
for(T item:oldList){
if(filter.match(item)){
newlist.add(item);
}
}
return newlist;
}
put it all together
List<Pojo> myList = ..
List<Pojo> redList = getFilteredList(myList,new Filter<Pojo>(){
public boolean match(Pojo item){ return item.isRed()};
});
List<Pojo> blueList = getFilteredList(myList,new Filter<Pojo>(){
public boolean match(Pojo item){ return item.COLOR== Color.BLUE};
});