Created
April 6, 2015 22:09
-
-
Save tomaszalusky/dcb695c5c3ae6d49b913 to your computer and use it in GitHub Desktop.
Java 8 type annotations experiments (see http://tomaszalusky.blogspot.cz/2015/04/tri-chytaky-k-typovym-anotacim-v-jave-8.html )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package anno; | |
import static java.util.stream.Collectors.toList; | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.annotation.Target; | |
import java.lang.reflect.AnnotatedArrayType; | |
import java.lang.reflect.AnnotatedElement; | |
import java.lang.reflect.AnnotatedParameterizedType; | |
import java.lang.reflect.AnnotatedType; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Parameter; | |
import java.util.List; | |
import java.util.stream.Stream; | |
/** | |
* This example shows the placement of type annotation on array types | |
* so as to have meaning equivalent to collections types. | |
* While annotations on collection types are intuitively read from left to right, | |
* annotations on arrays have different order due to syntax of array. | |
*/ | |
public abstract class TypeAnnotations { | |
// ------------------------------------------------------------------------- | |
// Nullable* is just for demonstration purpose, no null check is point of this example. | |
// Different Nullable* classes help to distinguish particular level of type nesting. | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE_USE,ElementType.PARAMETER}) | |
public static @interface NullableC {} // nullable container (array or collection) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE_USE,ElementType.PARAMETER}) | |
public static @interface Nullable1 {} // nullable thing in container | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE_USE,ElementType.PARAMETER}) | |
public static @interface Nullable2 {} // nullable thing in thing in container | |
// Name convention: l = List, a = array, n = Nullable, s = String | |
// Every two fields in following pairs are equivalent according to type annotations (e.g. the only difference is array vs. collection). | |
// -----------FIELDS-------------------------------------------------------- | |
List<@Nullable1 String> lns; | |
@Nullable1 String[] ans; | |
@NullableC List<String> nls; | |
String @NullableC [] nas; | |
@NullableC List<@Nullable1 String> nlns; | |
@Nullable1 String @NullableC [] nans; // note: annotation for deepest level is at the beginning | |
@NullableC List<@Nullable1 List<@Nullable2 String>> nlnlns; | |
@Nullable2 String @NullableC [] @Nullable1 [] nanans; // note: annotations for other levels are in front of [] and go from left to right | |
private static void testFields() throws Exception { | |
Field lns = field("lns"); | |
AnnotatedParameterizedType lns_t = (AnnotatedParameterizedType)lns.getAnnotatedType(); | |
System.out.println(at2s(lns_t) + " List of " + at2s(lns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Field ans = field("ans"); | |
AnnotatedArrayType ans_t = (AnnotatedArrayType)ans.getAnnotatedType(); | |
System.out.println(at2s(ans_t) + " array of " + at2s(ans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Field nls = field("nls"); | |
AnnotatedParameterizedType nls_t = (AnnotatedParameterizedType)nls.getAnnotatedType(); | |
System.out.println(at2s(nls_t) + " List of " + at2s(nls_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Field nas = field("nas"); | |
AnnotatedArrayType nas_t = (AnnotatedArrayType)nas.getAnnotatedType(); | |
System.out.println(at2s(nas_t) + " array of " + at2s(nas_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Field nlns = field("nlns"); | |
AnnotatedParameterizedType nlns_t = (AnnotatedParameterizedType)nlns.getAnnotatedType(); | |
System.out.println(at2s(nlns_t) + " List of " + at2s(nlns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Field nans = field("nans"); | |
AnnotatedArrayType nans_t = (AnnotatedArrayType)nans.getAnnotatedType(); | |
System.out.println(at2s(nans_t) + " array of " + at2s(nans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Field nlnlns = field("nlnlns"); | |
AnnotatedParameterizedType nlnlns_t = (AnnotatedParameterizedType)nlnlns.getAnnotatedType(); | |
AnnotatedParameterizedType nlnlns_tt = (AnnotatedParameterizedType)nlnlns_t.getAnnotatedActualTypeArguments()[0]; | |
System.out.println(at2s(nlnlns_t) + " List of " + at2s(nlnlns_tt) + " List of " + at2s(nlnlns_tt.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Field nanans = field("nanans"); | |
AnnotatedArrayType nanans_t = (AnnotatedArrayType)nanans.getAnnotatedType(); | |
AnnotatedArrayType nanans_tt = (AnnotatedArrayType)nanans_t.getAnnotatedGenericComponentType(); | |
System.out.println(at2s(nanans_t) + " array of " + at2s(nanans_tt) + " array of " + at2s(nanans_tt.getAnnotatedGenericComponentType()) + " Strings"); | |
} | |
static Field field(String name) throws Exception { | |
Field result = TypeAnnotations.class.getDeclaredField(name); | |
System.out.printf("field %-6s has annotations %-11s and type ", name, a2s(result)); | |
return result; | |
} | |
// -----------PARAMETERS---------------------------------------------------- | |
abstract void m( | |
List<@Nullable1 String> lns, | |
@Nullable1 String[] ans, | |
@NullableC List<String> nls, | |
String @NullableC [] nas, | |
@NullableC List<@Nullable1 String> nlns, | |
@Nullable1 String @NullableC [] nans, | |
@NullableC List<@Nullable1 List<@Nullable2 String>> nlnlns, | |
@Nullable2 String @NullableC [] @Nullable1 [] nanans | |
); | |
static final Method m = Stream.of(TypeAnnotations.class.getDeclaredMethods()) | |
.filter(mm -> "m".equals(mm.getName())).findFirst().get(); // I'm just lazy to enumerate all raw types and handle exception | |
static void testParameters() throws Exception { | |
Parameter lns = parameter("lns"); | |
AnnotatedParameterizedType lns_t = (AnnotatedParameterizedType)lns.getAnnotatedType(); | |
System.out.println(at2s(lns_t) + " List of " + at2s(lns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Parameter ans = parameter("ans"); | |
AnnotatedArrayType ans_t = (AnnotatedArrayType)ans.getAnnotatedType(); | |
System.out.println(at2s(ans_t) + " array of " + at2s(ans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Parameter nls = parameter("nls"); | |
AnnotatedParameterizedType nls_t = (AnnotatedParameterizedType)nls.getAnnotatedType(); | |
System.out.println(at2s(nls_t) + " List of " + at2s(nls_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Parameter nas = parameter("nas"); | |
AnnotatedArrayType nas_t = (AnnotatedArrayType)nas.getAnnotatedType(); | |
System.out.println(at2s(nas_t) + " array of " + at2s(nas_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Parameter nlns = parameter("nlns"); | |
AnnotatedParameterizedType nlns_t = (AnnotatedParameterizedType)nlns.getAnnotatedType(); | |
System.out.println(at2s(nlns_t) + " List of " + at2s(nlns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Parameter nans = parameter("nans"); | |
AnnotatedArrayType nans_t = (AnnotatedArrayType)nans.getAnnotatedType(); | |
System.out.println(at2s(nans_t) + " array of " + at2s(nans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Parameter nlnlns = parameter("nlnlns"); | |
AnnotatedParameterizedType nlnlns_t = (AnnotatedParameterizedType)nlnlns.getAnnotatedType(); | |
AnnotatedParameterizedType nlnlns_tt = (AnnotatedParameterizedType)nlnlns_t.getAnnotatedActualTypeArguments()[0]; | |
System.out.println(at2s(nlnlns_t) + " List of " + at2s(nlnlns_tt) + " List of " + at2s(nlnlns_tt.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Parameter nanans = parameter("nanans"); | |
AnnotatedArrayType nanans_t = (AnnotatedArrayType)nanans.getAnnotatedType(); | |
AnnotatedArrayType nanans_tt = (AnnotatedArrayType)nanans_t.getAnnotatedGenericComponentType(); | |
System.out.println(at2s(nanans_t) + " array of " + at2s(nanans_tt) + " array of " + at2s(nanans_tt.getAnnotatedGenericComponentType()) + " Strings"); | |
} | |
static Parameter parameter(String name) throws Exception { | |
Parameter result = Stream.of(m.getParameters()).filter(p -> p.getName().equals(name)).findFirst().get(); | |
System.out.printf("parameter %-6s has annotations %-11s and type ", name, a2s(result)); | |
return result; | |
} | |
// -----------METHODS------------------------------------------------------- | |
abstract List<@Nullable1 String> m_lns(); | |
abstract @Nullable1 String[] m_ans(); | |
abstract @NullableC List<String> m_nls(); | |
abstract String @NullableC [] m_nas(); | |
abstract @NullableC List<@Nullable1 String> m_nlns(); | |
abstract @Nullable1 String @NullableC [] m_nans(); | |
abstract @NullableC List<@Nullable1 List<@Nullable2 String>> m_nlnlns(); | |
abstract @Nullable2 String @NullableC [] @Nullable1 [] m_nanans(); | |
static void testMethods() throws Exception { | |
Method lns = method("lns"); | |
AnnotatedParameterizedType lns_t = (AnnotatedParameterizedType)lns.getAnnotatedReturnType(); | |
System.out.println(at2s(lns_t) + " List of " + at2s(lns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Method ans = method("ans"); | |
AnnotatedArrayType ans_t = (AnnotatedArrayType)ans.getAnnotatedReturnType(); | |
System.out.println(at2s(ans_t) + " array of " + at2s(ans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Method nls = method("nls"); | |
AnnotatedParameterizedType nls_t = (AnnotatedParameterizedType)nls.getAnnotatedReturnType(); | |
System.out.println(at2s(nls_t) + " List of " + at2s(nls_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Method nas = method("nas"); | |
AnnotatedArrayType nas_t = (AnnotatedArrayType)nas.getAnnotatedReturnType(); | |
System.out.println(at2s(nas_t) + " array of " + at2s(nas_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Method nlns = method("nlns"); | |
AnnotatedParameterizedType nlns_t = (AnnotatedParameterizedType)nlns.getAnnotatedReturnType(); | |
System.out.println(at2s(nlns_t) + " List of " + at2s(nlns_t.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Method nans = method("nans"); | |
AnnotatedArrayType nans_t = (AnnotatedArrayType)nans.getAnnotatedReturnType(); | |
System.out.println(at2s(nans_t) + " array of " + at2s(nans_t.getAnnotatedGenericComponentType()) + " Strings"); | |
Method nlnlns = method("nlnlns"); | |
AnnotatedParameterizedType nlnlns_t = (AnnotatedParameterizedType)nlnlns.getAnnotatedReturnType(); | |
AnnotatedParameterizedType nlnlns_tt = (AnnotatedParameterizedType)nlnlns_t.getAnnotatedActualTypeArguments()[0]; | |
System.out.println(at2s(nlnlns_t) + " List of " + at2s(nlnlns_tt) + " List of " + at2s(nlnlns_tt.getAnnotatedActualTypeArguments()[0]) + " Strings"); | |
Method nanans = method("nanans"); | |
AnnotatedArrayType nanans_t = (AnnotatedArrayType)nanans.getAnnotatedReturnType(); | |
AnnotatedArrayType nanans_tt = (AnnotatedArrayType)nanans_t.getAnnotatedGenericComponentType(); | |
System.out.println(at2s(nanans_t) + " array of " + at2s(nanans_tt) + " array of " + at2s(nanans_tt.getAnnotatedGenericComponentType()) + " Strings"); | |
} | |
static Method method(String name) throws Exception { | |
Method result = TypeAnnotations.class.getDeclaredMethod("m_" + name); | |
System.out.printf("method %-6s has annotations %-11s and type ", name, a2s(result)); | |
return result; | |
} | |
public static void main(String[] args) throws Exception { | |
System.out.printf("----------------------------------------------------%n"); | |
testFields(); | |
System.out.printf("----------------------------------------------------%n"); | |
testParameters(); | |
System.out.printf("----------------------------------------------------%n"); | |
testMethods(); | |
} | |
/** | |
* Dumps all simple class names of annotations of given annotated Java construct into String. | |
* @param o | |
* @return | |
*/ | |
static String a2s(AnnotatedElement o) { | |
String result = Stream.of(o.getAnnotations()).map(a -> a.annotationType().getSimpleName()).collect(toList()).toString(); | |
return result; | |
} | |
/** | |
* Dumps first annotation of given type (if any) to String. | |
* @param type | |
* @return | |
*/ | |
static String at2s(AnnotatedType type) { | |
return type.getAnnotations().length == 0 ? "annotationless" : type.getAnnotations()[0].annotationType().getSimpleName(); | |
} | |
} | |
/* OUTPUT: | |
---------------------------------------------------- | |
field lns has annotations [] and type annotationless List of Nullable1 Strings | |
field ans has annotations [Nullable1] and type annotationless array of Nullable1 Strings | |
field nls has annotations [NullableC] and type NullableC List of annotationless Strings | |
field nas has annotations [] and type NullableC array of annotationless Strings | |
field nlns has annotations [NullableC] and type NullableC List of Nullable1 Strings | |
field nans has annotations [Nullable1] and type NullableC array of Nullable1 Strings | |
field nlnlns has annotations [NullableC] and type NullableC List of Nullable1 List of Nullable2 Strings | |
field nanans has annotations [Nullable2] and type NullableC array of Nullable1 array of Nullable2 Strings | |
---------------------------------------------------- | |
parameter lns has annotations [] and type annotationless List of Nullable1 Strings | |
parameter ans has annotations [Nullable1] and type annotationless array of Nullable1 Strings | |
parameter nls has annotations [NullableC] and type NullableC List of annotationless Strings | |
parameter nas has annotations [] and type NullableC array of annotationless Strings | |
parameter nlns has annotations [NullableC] and type NullableC List of Nullable1 Strings | |
parameter nans has annotations [Nullable1] and type NullableC array of Nullable1 Strings | |
parameter nlnlns has annotations [NullableC] and type NullableC List of Nullable1 List of Nullable2 Strings | |
parameter nanans has annotations [Nullable2] and type NullableC array of Nullable1 array of Nullable2 Strings | |
---------------------------------------------------- | |
method lns has annotations [] and type annotationless List of Nullable1 Strings | |
method ans has annotations [Nullable1] and type annotationless array of Nullable1 Strings | |
method nls has annotations [NullableC] and type NullableC List of annotationless Strings | |
method nas has annotations [] and type NullableC array of annotationless Strings | |
method nlns has annotations [NullableC] and type NullableC List of Nullable1 Strings | |
method nans has annotations [Nullable1] and type NullableC array of Nullable1 Strings | |
method nlnlns has annotations [NullableC] and type NullableC List of Nullable1 List of Nullable2 Strings | |
method nanans has annotations [Nullable2] and type NullableC array of Nullable1 array of Nullable2 Strings | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment