I have an issue with generics types on class using JOOQ.
public abstract class BaseDataAccessObject<T extends BaseDataClass, U extends UpdatableRecord> {
protected abstract RecordMapper<U, T> getRecordMapper();
public T insert(T data) throws Exception{
//Some code ...
U record = getRecord(data);
record.store();
return record.map(getRecordMapper()); // <-- PROBLEM HERE !
}
}
Map accept one parameter of this type RecordMapper<Record, E> and it return an object of type E.
I face this issue :
Error:(110, 22) java: method map in interface org.jooq.Record cannot be applied to given types;
required : org.jooq.RecordMapper<org.jooq.Record,E>
found : org.jooq.RecordMapper<U,T>
reason: cannot infer type-variable(s) E argument mismatch; org.jooq.RecordMapper<U,T> cannot be converted to org.jooq.RecordMapper<org.jooq.Record,E>)
I don't understand why because :
Generic U, inherits form UpdatableRecord who inherits from org.jooq.Record, then Ushould be compatible with org.jooq.Record.
E should be compatible with T (no ancestor is defined).
I have to keep the U extending UpdatableRecord.
This Record.map(RecordMapper) method was a mistake from early days in jOOQ. It makes absolutely no sense at all to have a map method on a non-monadic type, i.e. on a non-wrapper type. E.g. Stream.map() is perfectly fine, because a stream can map its contents to something else, producing another stream. Optional.map() is perfectly fine, because an optional can map its contents to something else, producing another optional.
But an item / value shouldn't be able to map itself. There would have been a slight possibility to rectify this by using recursive generics, but that would have been an even bigger mistake.
But luckily, here's the solution to your problem, and it's really easy:
U record = getRecord(data);
record.store();
return getRecordMapper().map(record); // <-- PROBLEM HERE NO MORE !
Related
I have the following member in my class:
List<? extends SomeObject> list;
When I try to do:
list.add(list.get(0));
I get:
Test.java:7: error: no suitable method found for add(CAP#1)
list.add(list.get(0));
^
method Collection.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
method List.add(CAP#2) is not applicable
(argument mismatch; Object cannot be converted to CAP#2)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ? extends Object
CAP#2 extends Object from capture of ? extends Object
My question is twofold:
Why doesn't it compile? Why can't I pass get()'s result to add()?
And how can I achieve this in another way without resorting to casting?
I understand that in a method with <T extends SomeObject> I can't just say:
T someObject = list.get(0);
list.add(someObject);
since my T could be another extension than the ? extension.
I also understand I can't say:
List<? extends SomeObject> list1;
List<? extends SomeObject> list2;
list1.add(list2.get(0));
But since the add and the get should work with the same generic type in list.add(list.get(0)) I don't understand why the compiler doesn't accept it.
What I really need is
[something of type T where T is whatever was used to instantiate list] someObject = list.get(0);
list.add(someObject);
so that I can later
list.add(someObject);
I don't think I should have to template my whole class to achieve this, should I?
class MyClass<T extends SomeObject> {
List<T> list;
and then later a method with
T someObject = list.get(0);
of course works, but screws other parts of my code.
So the first question is why doesn't this work, second question is what's the best workaround?
My question is twofold, why can't I do:
list.add(list.get(0));
Because the compiler isn't smart enough to know that you're adding something from list back into list. The compiler doesn't consider list.get(0) to have anything to do with list once it is evaluated: it's just "some expression" of type ? extends SomeObject.
To solve this, add a method with its own type variable:
private <T> void addFirst(List<T> list) {
list.add(list.get(0));
}
and replace the original list.add(list.get(0)); with an invocation of this:
addFirst(list);
This only defines a type variable on the method, and does not need to be visible outside the class, so you don't need a class-level type variable.
It's perhaps worth pointing out this is analogous to the Collections.swap method: that's using set rather than add, but, from a generics point of view, it's the same thing:
#SuppressWarnings({"rawtypes", "unchecked"})
public static void swap(List<?> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
This takes an approach which is technically type-safe, and does avoid casts; but it's a bit gross, because it uses raw types.
I would imagine that it is only like this for backwards-compatibility reasons. Given a chance to write it again, you could just define a type variable as in the addFirst method above.
When use wildcards, we should follow The Get and Put Principle which introduced in Java Generics and Collections:
The Get and Put Principle: use an extends wildcard when you only get values out of a
structure, use a super wildcard when you only put values into a structure, and don’t use
a wildcard when you both get and put.
In your case, don't use a wildcard as you both get element from list and put element to list.
I'm trying to automatically bind factory classes with a certain annotation using jersey 2/HK2. Therefore, I get the provided type at runtime from a generic interface and then try to bind the factory to this type. The method that binds the factory to a class looks like this:
protected void bindResourceFactory(Class<? extends Factory<?>> factory) {
Class<?> providedClass = getProvidedClass(factory);
bindFactory(factory).to(providedClass).in(Singleton.class);
}
The bindFactoy method provided by HK2 is defined as following:
public <T> ServiceBindingBuilder<T> bindFactory(Class<? extends Factory<T>> factoryType) {
return resetBuilder(AbstractBindingBuilder.<T>createFactoryBinder(factoryType, null));
}
This seems to work well when I build everything with eclipse. However when I build the project with maven, I get the following build error:
[ERROR] /Users/jan/Documents/Workspace/jersey-test/bind/ResourceFactoryBinder.java:[32,5] no suitable method found for bindFactory(java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>>)
[ERROR] method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>,java.lang.Class<? extends java.lang.annotation.Annotation>) is not applicable
[ERROR] (cannot infer type-variable(s) T
[ERROR] (actual and formal argument lists differ in length))
[ERROR] method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>) is not applicable
[ERROR] (cannot infer type-variable(s) T
[ERROR] (argument mismatch; java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>> cannot be converted to java.lang.Class<? extends org.glassfish.hk2.api.Factory<T>>))
[ERROR] method org.glassfish.hk2.utilities.binding.AbstractBinder.<T>bindFactory(org.glassfish.hk2.api.Factory<T>) is not applicable
[ERROR] (cannot infer type-variable(s) T
[ERROR] (argument mismatch; java.lang.Class<capture#1 of ? extends org.glassfish.hk2.api.Factory<?>> cannot be converted to org.glassfish.hk2.api.Factory<T>))
The java version in both cases is 1.8.0_152.
The reason probably is that my argument used is of type Class<? extends Factory<?>> whereas bindFactory expects Class<? extends Factory<T>>. Does someone know, why this might build with eclipse but not with maven? And is there any way to make this work apart from calling bindFactory via reflection?
This happens because eclipse uses it's own compiler named ECJ, and maven uses the javac compiler. Sometimes code that compiles in ECJ does not compile in javac and vice versa.
In this particular case the eclipse compiler is able to infer the generic type T but javac isn't. So you need to explicity tell the type T, which is unknown because the received type is Class<? extends Factory<?>>, this means you should use Object like the following.
this.<Object>bindFactory((Class<? extends Factory<Object>>) factory);
In this case factory needs to be casted, and this.<Object> can be ommited because the compiler already infers Object.
Finally you could suppress the cast warning, and it's better to 'uncheck' as little code as possible.
#SuppressWarnings({ "unchecked" })
Class<? extends Factory<Object>> objFactory = (Class<? extends Factory<Object>>) factory;
bindFactory(objFactory).to(providedClass).in(Singleton.class);
One important thing to consider is that the method getProvidedClass(...) should return the class correctly
Also the use of generics in the method like this <T> void bindResourceFactory(Class<? extends Factory<T>>) would take you to the same place again, because you wouldn't be able to call the method with a class extending Factory<?> with a wildcard (Class<? extends Factory<?>>).
The reason this error happens is because the compiler doesn't capture convert the "inner" wildcard in Class<? extends Factory<?>> (the one in Factory<?>). (In terms of the specification, "capture conversion is not applied recursively".)
It's easier to explain why this should happen with a different (but analogous with respect to the kind of types involved) example. Suppose we have a List of any type of List:
List<List<?>> lists = ...;
Now suppose we have some method that processes lists of lists, but assumes that the lists all have the same type:
<T> void process(List<List<T>> lists) {
// and at this point we should note that List<T>
// allows us to add elements to the lists, so we
// could do something like this:
if (!lists.isEmpty()) {
List<T> list0 = lists.get(0);
for (int i = 1; i < lists.size(); ++i)
list0.addAll(lists.get(i));
}
}
So the question is: should we be able to pass our List<List<?>> to the process method? Well, it could be that we've built our list of lists in something like the following way:
List<Double> doubles = new ArrayList<>();
Collections.addAll(doubles, 0.0, 1.0, 2.0);
List<String> strings = new ArrayList<>();
Collections.addAll(strings, "X", "Y", "Z");
List<List<?>> lists = new ArrayList<>();
Collections.addAll(lists, strings, doubles);
In that case it's more obvious that we shouldn't be able to pass the List<List<?>> to the process method taking a List<List<T>>. The way this is actually accomplished by the compiler is that it won't capture the "inner" wildcard to some type variable T.
The code in the question doesn't compile for a pretty similar reason. Since the type parameter on Class is mainly relevant to methods related to constructors (and in particular the newInstance method), we could show an example that's more similar using Supplier:
static void example(Supplier<? extends Factory<?>> s) {
capture(s);
}
static <T> void capture(Supplier<? extends Factory<T>> s) {
Factory<T> a = s.get();
Factory<T> b = s.get();
// remember, a and b are supposed to have the same type
T obj = a.provide();
b.dispose(obj);
}
The problem is that since our supplier could originally be a Supplier<Factory<?>>, there's no reason it couldn't, say, return a Factory<String> from one invocation and a Factory<Double> from another. We therefore shouldn't be able to capture Supplier<Factory<?>> to Supplier<Factory<T>>. Class.newInstance will always return objects of the exact same type, but the compiler doesn't know that.
I think that Eclipse's compiler is probably just wrong in this case to compile the code in the question.
If you want to force this to compile, you could use unchecked casts as that user in the comments is suggesting, but I don't know enough about the classes involved to say whether the result of that is actually provably correct. The above two code examples show how doing something like that could actually go horribly wrong (in principle), but Class is sometimes a special case.
A way to fix it that's more proper would be to declare a type variable on bindResourceFactory so it takes a Class<? extends Factory<T>> too, but I don't know if that actually works for the way you're calling the method.
I have a Problem with a generic method after upgrading to Java 1.8, which was fine with Java 1.6 and 1.7
Consider the following code:
public class ExtraSortList<E> extends ArrayList<E> {
ExtraSortList(E... elements) {
super(Arrays.asList(elements));
}
public List<E> sortedCopy(Comparator<? super E> c) {
List<E> sorted = new ArrayList<E>(this);
Collections.sort(sorted, c);
return sorted;
}
public static void main(String[] args) {
ExtraSortList<String> stringList = new ExtraSortList<>("foo", "bar");
Comparator<? super String> compGen = null;
String firstGen = stringList.sortedCopy(compGen).get(0); // works fine
Comparator compRaw = null;
String firstRaw = stringList.sortedCopy(compRaw).get(0); // compiler ERROR: Type mismatch: cannot convert from Object to String
}
}
I tried this with the Oracle javac (1.8.0_92) and with Eclipse JDT (4.6.1) compiler. It is the same result for both. (the error message is a bit different, but essentially the same)
Beside the fact, that it is possible to prevent the error by avoiding raw types, it puzzles me, because i don't understand the reason.
Why does the raw method parameter of the sortedCopy-Method have any effect on the generic type of the return value? The generic type is already defined at class level. The method does not define a seperate generic type. The reference list is typed to <String>, so should the returned List.
Why does Java 8 discard the generic type from the class on the return value?
EDIT: If the method signature of sortedCopy is changed (as pointed out by biziclop) to
public List<E> sortedCopy(Comparator c) {
then the compiler does consider the generic type E from the type ExtraSortList<E> and no error appears. But now the parameter c is a raw type and thus the compiler cannot validate the generic type of the provided Comparator.
EDIT: I did some review of the Java Language Specification and now i think about, whether i have a lack of understanding or this is a flaw in the compiler. Because:
Scope of a Declaration of the generic type E is the class ExtraSortList, this includes the method sortedCopy.
The method sortedCopy itself does not declare a generic type variable, it just refers to the type variable E from the class scope. see Generic Methods in the JLS
The JLS also states in the same section
Type arguments may not need to be provided explicitly when a generic method is invoked, as they can often be inferred (§18 (Type Inference)).
The reference stringList is defined with String, thus the compiler does not need to infer a type forE on the invocation of sortedCopy because it is already defined.
Because stringList already has a reified type for E, the parameter c should be Comparator<? super String> for the given invocation.
The return type should also use the already reified type E, thus it should be List<String>.
This is my current understanding of how i think the Java compiler should evaluate the invocation. If i am wrong, an explanation why my assumptions are wrong would be nice.
To bring an final answer to why this happens:
Like #Jesper mentioned already, you're using raw types when you shouldn't (Especially when using the Generic as type in multiple cases).
Since you pass an Comparator without an Generic-Type, there will actually be none. You could think of the E-Generic as null to make it easier. Therefore your code becomes to this:
public List sortedCopy(Comparator c) {
List sorted = new ArrayList(this);
Collections.sort(sorted, c);
return sorted;
}
Now you're attemptig/assuming you get an String from an List without Generics and therefore an Object (hence it's the super-class of everything ).
To the question why the raw-type parameter has no effect on the return type, since you don't specify an certain Level of abstraction. You'd have to define an Type that the Generic has to extend/implement at least to make that happen (compilation errors), for example.
public class ExtraSortList<E extends String> extends ArrayList<E> {
will now only allow Strings or Classes which extend it (not possible here since string is final). With that, your fallback Type would be String.
Given the following example (using JUnit with Hamcrest matchers):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
This does not compile with the JUnit assertThat method signature of:
public static <T> void assertThat(T actual, Matcher<T> matcher)
The compiler error message is:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
However, if I change the assertThat method signature to:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Then the compilation works.
So three questions:
Why exactly doesn't the current version compile? Although I vaguely understand the covariance issues here, I certainly couldn't explain it if I had to.
Is there any downside in changing the assertThat method to Matcher<? extends T>? Are there other cases that would break if you did that?
Is there any point to the genericizing of the assertThat method in JUnit? The Matcher class doesn't seem to require it, since JUnit calls the matches method, which is not typed with any generic, and just looks like an attempt to force a type safety which doesn't do anything, as the Matcher will just not in fact match, and the test will fail regardless. No unsafe operations involved (or so it seems).
For reference, here is the JUnit implementation of assertThat:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
First - I have to direct you to http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html -- she does an amazing job.
The basic idea is that you use
<T extends SomeClass>
when the actual parameter can be SomeClass or any subtype of it.
In your example,
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
You're saying that expected can contain Class objects that represent any class that implements Serializable. Your result map says it can only hold Date class objects.
When you pass in result, you're setting T to exactly Map of String to Date class objects, which doesn't match Map of String to anything that's Serializable.
One thing to check -- are you sure you want Class<Date> and not Date? A map of String to Class<Date> doesn't sound terribly useful in general (all it can hold is Date.class as values rather than instances of Date)
As for genericizing assertThat, the idea is that the method can ensure that a Matcher that fits the result type is passed in.
Thanks to everyone who answered the question, it really helped clarify things for me. In the end Scott Stanchfield's answer got the closest to how I ended up understanding it, but since I didn't understand him when he first wrote it, I am trying to restate the problem so that hopefully someone else will benefit.
I'm going to restate the question in terms of List, since it has only one generic parameter and that will make it easier to understand.
The purpose of the parametrized class (such as List<Date> or Map<K, V> as in the example) is to force a downcast and to have the compiler guarantee that this is safe (no runtime exceptions).
Consider the case of List. The essence of my question is why a method that takes a type T and a List won't accept a List of something further down the chain of inheritance than T. Consider this contrived example:
List<java.util.Date> dateList = new ArrayList<java.util.Date>();
Serializable s = new String();
addGeneric(s, dateList);
....
private <T> void addGeneric(T element, List<T> list) {
list.add(element);
}
This will not compile, because the list parameter is a list of dates, not a list of strings. Generics would not be very useful if this did compile.
The same thing applies to a Map<String, Class<? extends Serializable>> It is not the same thing as a Map<String, Class<java.util.Date>>. They are not covariant, so if I wanted to take a value from the map containing date classes and put it into the map containing serializable elements, that is fine, but a method signature that says:
private <T> void genericAdd(T value, List<T> list)
Wants to be able to do both:
T x = list.get(0);
and
list.add(value);
In this case, even though the junit method doesn't actually care about these things, the method signature requires the covariance, which it is not getting, therefore it does not compile.
On the second question,
Matcher<? extends T>
Would have the downside of really accepting anything when T is an Object, which is not the APIs intent. The intent is to statically ensure that the matcher matches the actual object, and there is no way to exclude Object from that calculation.
The answer to the third question is that nothing would be lost, in terms of unchecked functionality (there would be no unsafe typecasting within the JUnit API if this method was not genericized), but they are trying to accomplish something else - statically ensure that the two parameters are likely to match.
EDIT (after further contemplation and experience):
One of the big issues with the assertThat method signature is attempts to equate a variable T with a generic parameter of T. That doesn't work, because they are not covariant. So for example you may have a T which is a List<String> but then pass a match that the compiler works out to Matcher<ArrayList<T>>. Now if it wasn't a type parameter, things would be fine, because List and ArrayList are covariant, but since Generics, as far as the compiler is concerned require ArrayList, it can't tolerate a List for reasons that I hope are clear from the above.
It boils down to:
Class<? extends Serializable> c1 = null;
Class<java.util.Date> d1 = null;
c1 = d1; // compiles
d1 = c1; // wont compile - would require cast to Date
You can see the Class reference c1 could contain a Long instance (since the underlying object at a given time could have been List<Long>), but obviously cannot be cast to a Date since there is no guarantee that the "unknown" class was Date. It is not typsesafe, so the compiler disallows it.
However, if we introduce some other object, say List (in your example this object is Matcher), then the following becomes true:
List<Class<? extends Serializable>> l1 = null;
List<Class<java.util.Date>> l2 = null;
l1 = l2; // wont compile
l2 = l1; // wont compile
...However, if the type of the List becomes ? extends T instead of T....
List<? extends Class<? extends Serializable>> l1 = null;
List<? extends Class<java.util.Date>> l2 = null;
l1 = l2; // compiles
l2 = l1; // won't compile
I think by changing Matcher<T> to Matcher<? extends T>, you are basically introducing the scenario similar to assigning l1 = l2;
It's still very confusing having nested wildcards, but hopefully that makes sense as to why it helps to understand generics by looking at how you can assign generic references to each other. It's also further confusing since the compiler is inferring the type of T when you make the function call (you are not explicitly telling it was T is).
The reason your original code doesn't compile is that <? extends Serializable> does not mean, "any class that extends Serializable," but "some unknown but specific class that extends Serializable."
For example, given the code as written, it is perfectly valid to assign new TreeMap<String, Long.class>() to expected. If the compiler allowed the code to compile, the assertThat() would presumably break because it would expect Date objects instead of the Long objects it finds in the map.
One way for me to understand wildcards is to think that the wildcard isn't specifying the type of the possible objects that given generic reference can "have", but the type of other generic references that it is is compatible with (this may sound confusing...) As such, the first answer is very misleading in it's wording.
In other words, List<? extends Serializable> means you can assign that reference to other Lists where the type is some unknown type which is or a subclass of Serializable. DO NOT think of it in terms of A SINGLE LIST being able to hold subclasses of Serializable (because that is incorrect semantics and leads to a misunderstanding of Generics).
I know this is an old question but I want to share an example that I think explains bounded wildcards pretty well. java.util.Collections offers this method:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
If we have a List of T, the List can, of course, contain instances of types that extend T. If the List contains Animals, the List can contain both Dogs and Cats (both Animals). Dogs have a property "woofVolume" and Cats have a property "meowVolume." While we might like to sort based upon these properties particular to subclasses of T, how can we expect this method to do that? A limitation of Comparator is that it can compare only two things of only one type (T). So, requiring simply a Comparator<T> would make this method usable. But, the creator of this method recognized that if something is a T, then it is also an instance of the superclasses of T. Therefore, he allows us to use a Comparator of T or any superclass of T, i.e. ? super T.
what if you use
Map<String, ? extends Class<? extends Serializable>> expected = null;
Please explain me why if I use the raw type A in the method test() , the get() method on my typed list returns an Object and not a B.:
public class test
{
public class B{}
public class C{}
public class A<T extends C>
{
private List<B> aBList;
public List<B> mGetBList()
{
return aBList;
}
}
public test(A pA) // Use of raw type - this is bad, I know!
{
B lB = pA.mGetBList().get(0); // Compile error: Type mismatch:
// cannot convert from Object to test.B
}
}
If I declare
public test(A<?> pA)
the get() method returns a B as expected.
+1 for interesting test case.
Looks like erasure erases everything, so in this case, you end up with.
public List mGetBList()
And erasure of List will result in public Object get( int ), which, of course, cannot be assigned to B.
If there is no strong need for raw type in method signature, use generic form that you have provided, otherwise cast the object to B
B lB = (B) pA.mGetBList().get(0);
"Doctor, it hurts when I do this."
Avoid raw types like the plague.
When you decalare your argument pa in the method test, no parameter is included, (including wildcard ). Therefore the list is held in a variable which contains a list of objects, so when you try to extract an element from the list you get a object, so you would have to cast it back to the required type, in this case B.
When using a wildcard the compliler is told not promote the list to a varibale containing an list holding Object. It is told that the contents are of the list are of 'unknown type' and is to be left alone. It is then upto the programmer to ensure that when extracting an element it is assigned to a suitable varibale, without using a cast.
Ive been doing some digging around ang found this.
http://java.sun.com/docs/books/tutorial/extra/generics/legacy.html
Basically, erasure gets rid of (or erases) all generic type information. All the type information betweeen angle brackets is thrown out, so, for example, a parameterized type like List is converted into List. All remaining uses of type variables are replaced by the upper bound of the type variable (usually Object).
By upper bound im taking it if they mean < T extends C>, C would be the upper bound, then as only B is the type varibable for aBlist then its upper bound would be Object.
Anway hope this helps (Please dont mark me down again).