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    *      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 }