View Javadoc
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    *      http://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>
32   * class Typesafe {
33   *   &lt;T&gt; T obtain(Class&lt;T&gt; type, ...);
34   * }
35   * </pre>
36   * Consumed in the manner of:
37   * <pre>
38   * Foo foo = typesafe.obtain(Foo.class, ...);
39   * </pre>
40   * Yet, you run into problems when you want to do this with a parameterized type:
41   * <pre>
42   * List&lt;String&gt; listOfString = typesafe.obtain(List.class, ...); // could only give us a raw List
43   * </pre>
44   * {@code java.lang.reflect.Type} might provide some value:
45   * <pre>
46   * Type listOfStringType = ...; // firstly, how to obtain this? Doable, but not straightforward.
47   * List&lt;String&gt; listOfString = (List&lt;String&gt;) typesafe.obtain(listOfStringType, ...); // nongeneric Type would necessitate a cast
48   * </pre>
49   * The "type literal" concept was introduced to provide an alternative, i.e.:
50   * <pre>
51   * class Typesafe {
52   *   &lt;T&gt; T obtain(TypeLiteral&lt;T&gt; type, ...);
53   * }
54   * </pre>
55   * Consuming code looks like:
56   * <pre>
57   * List&lt;String&gt; listOfString = typesafe.obtain(new TypeLiteral&lt;List&lt;String&gt;&gt;() {}, ...);
58   * </pre>
59   * <p>
60   * This has the effect of "jumping up" a level to tie a {@code java.lang.reflect.Type}
61   * to a type variable while simultaneously making it short work to obtain a
62   * {@link Type} instance for any given type, inline.
63   * </p>
64   * <p>Additionally {@link TypeLiteral} implements the {@link Typed} interface which
65   * is a generalization of this concept, and which may be implemented in custom classes.
66   * It is suggested that APIs be defined in terms of the interface, in the following manner:
67   * </p>
68   * <pre>
69   *   &lt;T&gt; T obtain(Typed&lt;T&gt; typed, ...);
70   * </pre>
71   *
72   * @param <T> the type
73   * @since 3.2
74   */
75  public abstract class TypeLiteral<T> implements Typed<T> {
76  
77      @SuppressWarnings("rawtypes")
78      private static final TypeVariable<Class<TypeLiteral>> T = TypeLiteral.class.getTypeParameters()[0];
79  
80      /**
81       * Represented type.
82       */
83      public final Type value;
84  
85      private final String toString;
86  
87      /**
88       * The default constructor.
89       */
90      protected TypeLiteral() {
91          this.value =
92              Validate.notNull(TypeUtils.getTypeArguments(getClass(), TypeLiteral.class).get(T),
93                  "%s does not assign type parameter %s", getClass(), TypeUtils.toLongString(T));
94  
95          this.toString = String.format("%s<%s>", TypeLiteral.class.getSimpleName(), TypeUtils.toString(value));
96      }
97  
98      @Override
99      public final boolean equals(final Object obj) {
100         if (obj == this) {
101             return true;
102         }
103         if (!(obj instanceof TypeLiteral)) {
104             return false;
105         }
106         final TypeLiteral<?> other = (TypeLiteral<?>) obj;
107         return TypeUtils.equals(value, other.value);
108     }
109 
110     @Override
111     public Type getType() {
112         return value;
113     }
114 
115     @Override
116     public int hashCode() {
117         return 37 << 4 | value.hashCode();
118     }
119 
120     @Override
121     public String toString() {
122         return toString;
123     }
124 }