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 * <T> T obtain(Class<T> 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<String> 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<String> listOfString = (List<String>) 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 * <T> T obtain(TypeLiteral<T> type, ...); 53 * } 54 * </pre> 55 * Consuming code looks like: 56 * <pre> 57 * List<String> listOfString = typesafe.obtain(new TypeLiteral<List<String>>() {}, ...); 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 * <T> T obtain(Typed<T> 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 }