001 package javax.ws.rs.core;
002
003 /*
004 * The contents of this file are subject to the terms
005 * of the Common Development and Distribution License
006 * (the "License"). You may not use this file except
007 * in compliance with the License.
008 *
009 * You can obtain a copy of the license at
010 * http://www.opensource.org/licenses/cddl1.php
011 * See the License for the specific language governing
012 * permissions and limitations under the License.
013 *
014 * This file incorporates work covered by the following copyright and
015 * permission notice:
016 *
017 * Copyright (C) 2006 Google Inc.
018 *
019 * Licensed under the Apache License, Version 2.0 (the "License");
020 * you may not use this file except in compliance with the License.
021 * You may obtain a copy of the License at
022 *
023 * http://www.apache.org/licenses/LICENSE-2.0
024 *
025 * Unless required by applicable law or agreed to in writing, software
026 * distributed under the License is distributed on an "AS IS" BASIS,
027 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
028 * See the License for the specific language governing permissions and
029 * limitations under the License.
030 */
031 import java.lang.reflect.GenericArrayType;
032 import java.lang.reflect.ParameterizedType;
033 import java.lang.reflect.Type;
034 import javax.ws.rs.ext.MessageBodyWriter;
035
036 /**
037 * Represents a response entity of a generic type {@code T}.
038 *
039 * <p>Normally type erasure removes generic type information such that a
040 * {@link Response} instance that contains, e.g., an entity of type
041 * {@code List<String>} appears to contain a raw {@code List<?>} at runtime.
042 * When the generic type is required to select a suitable
043 * {@link MessageBodyWriter}, this class may be used to wrap the entity and
044 * capture its generic type.</p>
045 *
046 * <p>There are two ways to create an instance:</p>
047 * <ol>
048 * <li>Create a (typically anonymous) subclass of this
049 * class which enables retrieval of the type information at runtime despite
050 * type erasure. For example, the following code shows how to create a
051 * {@link Response} containing an entity of type {@code List<String>} whose
052 * generic type will be available at runtime for selection of a suitable
053 * {@link MessageBodyWriter}:
054 *
055 * <pre>List<String> list = new ArrayList<String>();
056 *GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) {};
057 *Response response = Response.ok(entity).build();</pre>
058 *
059 * <p>where <code>list</code> is the instance of <code>List<String></code>
060 * that will form the response body and entity is an instance of an anonymous
061 * subclass of {@code GenericEntity}.</p></li>
062 * <li>Create an instance directly by supplying the generic type information
063 * with the entity. For example the following code shows how to create
064 * a response containing the result of a method invoked via reflection:
065 * <pre>Method method = ...;
066 *GenericEntity<Object> entity = new GenericEntity<Object>(
067 * method.invoke(...), method.getGenericReturnType());
068 *Response response = Response.ok(entity).build();</pre></li>
069 * <p>The above obtains the generic type from the return type of the method,
070 * the raw type is the class of entity.</p>
071 * </ol>
072 */
073 public class GenericEntity<T> {
074
075 final Class<?> rawType;
076 final Type type;
077 final T entity;
078
079 /**
080 * Constructs a new generic entity. Derives represented class from type
081 * parameter. Note that this constructor is protected, users should create
082 * a (usually anonymous) subclass as shown above.
083 *
084 * @param entity the entity instance, must not be null
085 * @throws IllegalArgumentException if entity is null
086 */
087 protected GenericEntity(T entity) {
088 if (entity == null) {
089 throw new IllegalArgumentException("The entity must not be null");
090 }
091 this.entity = entity;
092 this.type = getSuperclassTypeParameter(getClass());
093 this.rawType = entity.getClass();
094 }
095
096 /**
097 * Create a new instance of GenericEntity, supplying the generic type
098 * information. The entity must be assignable to a variable of the
099 * supplied generic type, e.g. if {@code entity} is an instance of
100 * {@code ArrayList<String>} then {@code genericType} could
101 * be the same or a superclass of {@code ArrayList} with the same generic
102 * type like {@code List<String>}.
103 * @param entity the entity instance, must not be null
104 * @param genericType the generic type, must not be null
105 * @throws IllegalArgumentException if the entity is not assignable to
106 * a variable of the supplied generic type or if entity or genericType
107 * is null.
108 */
109 public GenericEntity(T entity, Type genericType) {
110 if (entity == null || genericType==null) {
111 throw new IllegalArgumentException("Arguments must not be null");
112 }
113 this.entity = entity;
114 this.rawType = entity.getClass();
115 checkTypeCompatibility(this.rawType, genericType);
116 this.type = genericType;
117 }
118
119 private void checkTypeCompatibility(Class<?> c, Type t) {
120 if (t instanceof Class) {
121 Class<?> ct = (Class<?>)t;
122 if (ct.isAssignableFrom(c))
123 return;
124 } else if (t instanceof ParameterizedType) {
125 ParameterizedType pt = (ParameterizedType)t;
126 Type rt = pt.getRawType();
127 checkTypeCompatibility(c, rt);
128 return;
129 } else if (c.isArray() && (t instanceof GenericArrayType)) {
130 GenericArrayType at = (GenericArrayType)t;
131 Type rt = at.getGenericComponentType();
132 checkTypeCompatibility(c.getComponentType(), rt);
133 return;
134 }
135 throw new IllegalArgumentException("The type is incompatible with the class of the entity");
136 }
137
138 /**
139 * Returns the type from super class's type parameter.
140 */
141 private static Type getSuperclassTypeParameter(Class<?> subclass) {
142 Type superclass = subclass.getGenericSuperclass();
143 if (!(superclass instanceof ParameterizedType)) {
144 throw new RuntimeException("Missing type parameter.");
145 }
146 ParameterizedType parameterized = (ParameterizedType) superclass;
147 return parameterized.getActualTypeArguments()[0];
148 }
149
150 /**
151 * Gets the raw type of the enclosed entity. Note that this is the raw type of
152 * the instance, not the raw type of the type parameter. I.e. in the example
153 * in the introduction, the raw type is {@code ArrayList} not {@code List}.
154 * @return the raw type
155 */
156 public final Class<?> getRawType() {
157 return rawType;
158 }
159
160 /**
161 * Gets underlying {@code Type} instance. Note that this is derived from the
162 * type parameter, not the enclosed instance. I.e. in the example
163 * in the introduction, the type is {@code List<String>} not
164 * {@code ArrayList<String>}.
165 * @return the type
166 */
167 public final Type getType() {
168 return type;
169 }
170
171 /**
172 * Get the enclosed entity
173 * @return the enclosed entity
174 */
175 public final T getEntity() {
176 return entity;
177 }
178 }