1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3.reflect;
18
19 import java.lang.reflect.Type;
20 import java.lang.reflect.TypeVariable;
21
22 import org.apache.commons.lang3.Validate;
23
24 /**
25 * Type literal comparable to {@code javax.enterprise.util.TypeLiteral},
26 * made generally available outside the JEE context. Allows the passing around of
27 * a "token" that represents a type in a typesafe manner, as opposed to
28 * passing the (non-parameterized) {@link Type} object itself. Consider:
29 * <p>
30 * You might see such a typesafe API as:
31 * <pre>{@code
32 * class Typesafe {
33 * <T> T obtain(Class<T> type, ...);
34 * }
35 * }
36 * </pre>
37 * Consumed in the manner of:
38 * <pre>
39 * Foo foo = typesafe.obtain(Foo.class, ...);
40 * </pre>
41 * Yet, you run into problems when you want to do this with a parameterized type:
42 * <pre>{@code
43 * List<String> listOfString = typesafe.obtain(List.class, ...); // could only give us a raw List
44 * }</pre>
45 * {@link java.lang.reflect.Type} might provide some value:
46 * <pre>{@code
47 * Type listOfStringType = ...; // firstly, how to obtain this? Doable, but not straightforward.
48 * List<String> listOfString = (List<String>) typesafe.obtain(listOfStringType, ...); // nongeneric Type would necessitate a cast
49 * }</pre>
50 * The "type literal" concept was introduced to provide an alternative, i.e.:
51 * <pre>{@code
52 * class Typesafe {
53 * <T> T obtain(TypeLiteral<T> type, ...);
54 * }
55 * }</pre>
56 * Consuming code looks like:
57 * <pre>{@code
58 * List<String> listOfString = typesafe.obtain(new TypeLiteral<List<String>>() {}, ...);
59 * }</pre>
60 * <p>
61 * This has the effect of "jumping up" a level to tie a {@link java.lang.reflect.Type}
62 * to a type variable while simultaneously making it short work to obtain a
63 * {@link Type} instance for any given type, inline.
64 * </p>
65 * <p>Additionally {@link TypeLiteral} implements the {@link Typed} interface which
66 * is a generalization of this concept, and which may be implemented in custom classes.
67 * It is suggested that APIs be defined in terms of the interface, in the following manner:
68 * </p>
69 * <pre>{@code
70 * <T> T obtain(Typed<T> typed, ...);
71 * }</pre>
72 *
73 * @param <T> the type
74 * @since 3.2
75 */
76 public abstract class TypeLiteral<T> implements Typed<T> {
77
78 @SuppressWarnings("rawtypes")
79 private static final TypeVariable<Class<TypeLiteral>> T = TypeLiteral.class.getTypeParameters()[0];
80
81 /**
82 * Represented type.
83 */
84 public final Type value;
85
86 private final String toString;
87
88 /**
89 * Constructs a new instance.
90 */
91 protected TypeLiteral() {
92 this.value = Validate.notNull(TypeUtils.getTypeArguments(getClass(), TypeLiteral.class).get(T),
93 "%s does not assign type parameter %s", getClass(), TypeUtils.toLongString(T));
94 this.toString = String.format("%s<%s>", TypeLiteral.class.getSimpleName(), TypeUtils.toString(value));
95 }
96
97 @Override
98 public final boolean equals(final Object obj) {
99 if (obj == this) {
100 return true;
101 }
102 if (!(obj instanceof TypeLiteral)) {
103 return false;
104 }
105 final TypeLiteral<?> other = (TypeLiteral<?>) obj;
106 return TypeUtils.equals(value, other.value);
107 }
108
109 @Override
110 public Type getType() {
111 return value;
112 }
113
114 @Override
115 public int hashCode() {
116 return 37 << 4 | value.hashCode();
117 }
118
119 @Override
120 public String toString() {
121 return toString;
122 }
123 }