I have come across a curious syntax today. The code is from Gradle's source files you can find it in src/core-impl/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java
private class ConfigurationResolvableDependencies implements ResolvableDependencies {
public FileCollection getFiles() {
return DefaultConfiguration.this.fileCollection(Specs.<Dependency>satisfyAll());
}
}
Is someone able to explain the purpose of this strange generics syntax. If this is a repeat, then please forgive me as i do not know what to call this for searching purposes.
The syntax here is because the Specs class's satisfyAll method is static, so the Generics syntax there is specifying the type to use for the static method.
See this for the API doc: http://www.gradle.org/docs/current/javadoc/org/gradle/api/specs/Specs.html#satisfyAll%28%29
Silly me, just read the documentation on the oracle website, This type of syntax is referred to as Type Witnessing and it is used when a generic method with generic types is defined as so:
public class BoxDemo {
public static <U> void addBox(U u, List<Box<U>> boxes) {
Box<U> box = new Box<>();
box.set(u);
boxes.add(box);
}
}
The method may be called with an additional specifier telling the compiler to infer the argument type of the first and second parameter:
List<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
BoxDemo.<Integer>addBox(Integer.valueOf(20), listOfIntegerBoxes);
also from the documentation:
Alternatively, if you omit the type witness,a Java compiler automatically infers (from the method's arguments) that the type parameter is Integer:
BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes);
Related
Assume I want to inspect the following class using reflection:
class Foo {
void bar(List<#Important String> b) {}
}
Note that the #Important annotation is not on the argument itself (then I could use Method.getParameterAnnotations()), but on its type parameter (which is allowed when the annotation is declared to have ElementType.TYPE_USE).
Is there a way to read such annotations in Java 11?
Unfortunately, this part of the Reflection API is horrible. The base types do not have the necessary query methods and there is no Visitor API or such alike. So any code trying to do a full introspection has no choice but to perform lots of instanceof checks, to handle all possible cases.
If you know beforehand that the method’s type should be a parameterized type and you only want to check the annotations of its first type argument, you can do it a bit simpler, ignoring all other possible cases:
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.Method;
import java.util.*;
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
Method m = Foo.class.getDeclaredMethod("bar", List.class);
var at = m.getAnnotatedParameterTypes()[0];
var ata = ((AnnotatedParameterizedType)at).getAnnotatedActualTypeArguments()[0];
// get all annotations
for(var a: ata.getAnnotations()) {
System.out.println(a);
}
// or check the presence of a known annotation
System.out.println(ata.getAnnotation(Important.class) != null);
}
class Foo {
void bar(List<#Important String> b) {}
}
}
Demo on Ideone
#Important()
true
TL;DR — See this answer discussing the subtle differences between type parameters, type variables and type arguments.
The long-winded version
„…Note that the #Important annotation is…on its type parameter…“
In your Foo declaration…
class Foo {
void bar(List<#Important String> b) {}
}
…String is not a type parameter. Nor is it a type variable. In your snippet there String is a type argument.
Though I stand corrected on saying originally that ReferenceType type arguments can't have annotations (turns out they can) I'll leave these JLS productions here to keep me humble…
4.5.1. Type Arguments of Parameterized Types
Type arguments may be either reference types or wildcards. Wildcards are useful
in situations where only partial knowledge about the type parameter is required.
TypeArguments:
< TypeArgumentList >
TypeArgumentList:
TypeArgument {, TypeArgument}
TypeArgument:
ReferenceType Wildcard
Wildcard:
{Annotation} ? [WildcardBounds]
WildcardBounds:
extends ReferenceType
super ReferenceType
For completeness, the JLS production for type parameters…
4.4. Type Variables
A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.
A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor…
TypeParameter:
{TypeParameterModifier} TypeIdentifier [TypeBound]:
TypeParameterModifier:
Annotation
…
Although I've never seen one in the wild — until today — the preceding JLS productions confirm that the annotated String type argument in your snippet is, indeed, legal Java. Learn something new everyday!
I'm doing a series of streaming operations to flatten what's effectively a 2D array.
Arrays.stream(attributes)
.map(Attribute::getCommand)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap((array) -> (Arrays.stream((String[]) array)))
.toArray(String[]::new)
Where Attribute conforms to the following interface:
public interface Attribute<T> {
Optional<String[]> getCommand();
}
However, the final flatMap() call isn't operating as expected.
.flatMap((array) -> (Arrays.stream((String[]) array))) works just fine.
.flatMap((array) -> (Arrays.stream(array))) fails to compile with java: no suitable method found for stream(java.lang.Object).
.flatMap(Arrays::stream) fails to compile with java: incompatible types: cannot infer type-variable(s) T (argument mismatch; java.lang.Object cannot be converted to T[]).
It seems to me that the type should be inferred just fine though. IntelliJ agrees and marks the cast as redundant and shows no compile errors with any of the three implementations. Why does Java require this apparently redundant typecast?
I additionally tried the following minimalist implementation:
import java.util.Arrays;
import java.util.Optional;
public class Streaming {
public static void main(String[] args) {
Optional<String[]>[] myarray = new Optional[]{Optional.of(new String[]{"Hello", "world"}),
Optional.empty(), Optional.of(new String[]{"Foo"})};
System.out.println(Arrays.toString(Arrays.stream(myarray).filter(Optional::isPresent).map
(Optional::get).flatMap(Arrays::stream).toArray(String[]::new)));
}
}
And it works just fine with all three implementations, outputting the expected [Hello, world, Foo].
Edit:
This was marked as a duplicate of this question. I may be wrong, but it seems that there's a distinction since this the type is specified in a more explicit manner. Notably, IntelliJ agrees that the cast is necessary in the example provided on said post, but not for my code. If I am mistaken, please let me know.
Edit:
Per request, the declaration of attributes is Attribute[] attributes = new Attribute[]{...} where ... is a variety of implementations of Attribute.
Attribute is a generic class (I wonder why as T is not used).
If you have this error it means that you declared a raw type of that such as :
Attribute[] attributes = ...;
For a raw type, the return type of getCommand() that is declared as Optional<String[]> becomes just Optional.
Declare Attribute as a generic type, for example : Attribute<String>[] attributes = ...; and this should compile without the cast or just remove the parameterized type T if it is not required.
I am working on generics and found that the following code is giving compile time error at comparing method.
Multiple markers at this line
- Cannot infer type argument(s) for comparing(Function)
- The type A does not define m1(Object) that is applicable here
class A<T> {
String m1() {
return null;
}
}
class B {
void test() {
Comparator<A<String>> target = Comparator.comparing(A::m1).thenComparing(A::m1);
}
}
Can some one help me understand this behavior; and how can I fix the problem?
If you specify the exact generic types at the comparing method, the code compiles.
Comparator<A<String>> target =
Comparator.<A<String>, String>comparing(A::m1).thenComparing(A::m1);
You should specify type parameter for class A.
Comparator<A<String>> target = Comparator.comparing(A<String>::m1).thenComparing(A<String>::m1);
Interesting question. Haven't gone into JLS but I guess type inference does not work in case of chained method call. (You can see it works for a simple Comparator<A<String>> target = Comparator.comparing(A<String>::m1); )
One quick fix, which is similar to another answer, is help Java do the type inference:
Comparator<A<String>> target = Comparator.comparing(A<String>::m1)
.thenComparing(A::m1);
Please note doing it at the first method already do the trick.
(Looking forward to see if someone can dig out JLS to see if such inference is supposed to be valid :P )
you can nested as
Comparator<A<String>> target1 = Comparator.comparing(A::m1);
Comparator<A<String>> target2 = target1.thenComparing(A::m1);
myVarList.sort(target2);
Comparator<A<String>> target = Comparator.comparing(A::m1).thenComparing(A::m1);
thenComparing() expects a Comparator object as parameter...
Suppose I have a Java class hierarchy defined as follow:
interface Bar<T> {}
class Foo<A,B> implements Bar<B> {}
How can I programmatically assess (using reflection) that the type parameter of Bar in Foo is the second of foo's parameters and not the first (B instead of A)?
I've tried using TypeVariable#getName() in order to compare the names, but when I apply getGenericInterfaces() to Foo<A,B> I get Bar<T> and not Bar<B>
Solution (thanks to #LouisWasserman): use Foo.class.getGeenricInterfaces()[0].getActualTypeParameters() returns the correct TypeVariable (B instead of T, in the previous example)
well using TypeVariable#getName() return the type as it appears in the source code in your case it's normal to get Bar<T>. TypeVariable Doc
Using reflection in generic Classes can't help, because of Type Erasure. Erasure of Generic Types
I've the same issue in some personal projects, I tried to change the design of my class, have a look at the example below:
Instead of this:
public class Mapper<T> {
public Mapper(){
}
}
I used this:
public class Mapper {
private Class<?> entityClazz;
public Mapper(Class<?> entity){
this.entityClazz = entity
//Here I've donne all reflection issues i want !
}
}
You can use Class#isAssignableFrom() Doc to test assignability between Class Objects.
I hope this helps, good luck !
I'm looking at some Java reflection sourcecode that goes like this:
Method fixTransparentPixels = TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", new Class[] { [[I.class });
The method being referenced is declared like so:
private void fixTransparentPixels(int[][] p_147961_1_) {...}
What I do not understand is the [[I.class part. Now, I get that the actual Class[] array is to determine which form of the declared method you want (what parameter types etc.), but what does [[I.class actually mean?
Furthermore, when I try to write this reflection code myself, my IDE gives me syntax errors on the [[I.class bit. Can anyone give me any info on this?
Cheers.
When using getDeclaredMethod(String name, Class<?>... parameterTypes) the parameterTypes must be the class of the parameter (obviously). So in this case fixTransparentPixels require a int[][], so the parameterTypes will be int[][].class.
This will works :
TextureAtlasSprite.class.getDeclaredMethod("fixTransparentPixels", int[][].class);
[[I is the internal name of the class for int[][]:
System.out.println(int[][].class.getName()); outputs [[I
or Class.forName("[[I") == int[][].class.
However, it's illegal to write [[I.class in source code. You should write int[][].class instead.