| package javax.ws.rs.core; |
| |
| /* |
| * The contents of this file are subject to the terms |
| * of the Common Development and Distribution License |
| * (the "License"). You may not use this file except |
| * in compliance with the License. |
| * |
| * You can obtain a copy of the license at |
| * http://www.opensource.org/licenses/cddl1.php |
| * See the License for the specific language governing |
| * permissions and limitations under the License. |
| * |
| * This file incorporates work covered by the following copyright and |
| * permission notice: |
| * |
| * Copyright (C) 2006 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| import java.lang.reflect.GenericArrayType; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import javax.ws.rs.ext.MessageBodyWriter; |
| |
| /** |
| * Represents a response entity of a generic type {@code T}. |
| * |
| * <p>Normally type erasure removes generic type information such that a |
| * {@link Response} instance that contains, e.g., an entity of type |
| * {@code List<String>} appears to contain a raw {@code List<?>} at runtime. |
| * When the generic type is required to select a suitable |
| * {@link MessageBodyWriter}, this class may be used to wrap the entity and |
| * capture its generic type.</p> |
| * |
| * <p>There are two ways to create an instance:</p> |
| * <ol> |
| * <li>Create a (typically anonymous) subclass of this |
| * class which enables retrieval of the type information at runtime despite |
| * type erasure. For example, the following code shows how to create a |
| * {@link Response} containing an entity of type {@code List<String>} whose |
| * generic type will be available at runtime for selection of a suitable |
| * {@link MessageBodyWriter}: |
| * |
| * <pre>List<String> list = new ArrayList<String>(); |
| *GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) {}; |
| *Response response = Response.ok(entity).build();</pre> |
| * |
| * <p>where <code>list</code> is the instance of <code>List<String></code> |
| * that will form the response body and entity is an instance of an anonymous |
| * subclass of {@code GenericEntity}.</p></li> |
| * <li>Create an instance directly by supplying the generic type information |
| * with the entity. For example the following code shows how to create |
| * a response containing the result of a method invoked via reflection: |
| * <pre>Method method = ...; |
| *GenericEntity<Object> entity = new GenericEntity<Object>( |
| * method.invoke(...), method.getGenericReturnType()); |
| *Response response = Response.ok(entity).build();</pre></li> |
| * <p>The above obtains the generic type from the return type of the method, |
| * the raw type is the class of entity.</p> |
| * </ol> |
| */ |
| public class GenericEntity<T> { |
| |
| final Class<?> rawType; |
| final Type type; |
| final T entity; |
| |
| /** |
| * Constructs a new generic entity. Derives represented class from type |
| * parameter. Note that this constructor is protected, users should create |
| * a (usually anonymous) subclass as shown above. |
| * |
| * @param entity the entity instance, must not be null |
| * @throws IllegalArgumentException if entity is null |
| */ |
| protected GenericEntity(T entity) { |
| if (entity == null) { |
| throw new IllegalArgumentException("The entity must not be null"); |
| } |
| this.entity = entity; |
| this.type = getSuperclassTypeParameter(getClass()); |
| this.rawType = entity.getClass(); |
| } |
| |
| /** |
| * Create a new instance of GenericEntity, supplying the generic type |
| * information. The entity must be assignable to a variable of the |
| * supplied generic type, e.g. if {@code entity} is an instance of |
| * {@code ArrayList<String>} then {@code genericType} could |
| * be the same or a superclass of {@code ArrayList} with the same generic |
| * type like {@code List<String>}. |
| * @param entity the entity instance, must not be null |
| * @param genericType the generic type, must not be null |
| * @throws IllegalArgumentException if the entity is not assignable to |
| * a variable of the supplied generic type or if entity or genericType |
| * is null. |
| */ |
| public GenericEntity(T entity, Type genericType) { |
| if (entity == null || genericType==null) { |
| throw new IllegalArgumentException("Arguments must not be null"); |
| } |
| this.entity = entity; |
| this.rawType = entity.getClass(); |
| checkTypeCompatibility(this.rawType, genericType); |
| this.type = genericType; |
| } |
| |
| private void checkTypeCompatibility(Class<?> c, Type t) { |
| if (t instanceof Class) { |
| Class<?> ct = (Class<?>)t; |
| if (ct.isAssignableFrom(c)) |
| return; |
| } else if (t instanceof ParameterizedType) { |
| ParameterizedType pt = (ParameterizedType)t; |
| Type rt = pt.getRawType(); |
| checkTypeCompatibility(c, rt); |
| return; |
| } else if (c.isArray() && (t instanceof GenericArrayType)) { |
| GenericArrayType at = (GenericArrayType)t; |
| Type rt = at.getGenericComponentType(); |
| checkTypeCompatibility(c.getComponentType(), rt); |
| return; |
| } |
| throw new IllegalArgumentException("The type is incompatible with the class of the entity"); |
| } |
| |
| /** |
| * Returns the type from super class's type parameter. |
| */ |
| private static Type getSuperclassTypeParameter(Class<?> subclass) { |
| Type superclass = subclass.getGenericSuperclass(); |
| if (!(superclass instanceof ParameterizedType)) { |
| throw new RuntimeException("Missing type parameter."); |
| } |
| ParameterizedType parameterized = (ParameterizedType) superclass; |
| return parameterized.getActualTypeArguments()[0]; |
| } |
| |
| /** |
| * Gets the raw type of the enclosed entity. Note that this is the raw type of |
| * the instance, not the raw type of the type parameter. I.e. in the example |
| * in the introduction, the raw type is {@code ArrayList} not {@code List}. |
| * @return the raw type |
| */ |
| public final Class<?> getRawType() { |
| return rawType; |
| } |
| |
| /** |
| * Gets underlying {@code Type} instance. Note that this is derived from the |
| * type parameter, not the enclosed instance. I.e. in the example |
| * in the introduction, the type is {@code List<String>} not |
| * {@code ArrayList<String>}. |
| * @return the type |
| */ |
| public final Type getType() { |
| return type; |
| } |
| |
| /** |
| * Get the enclosed entity |
| * @return the enclosed entity |
| */ |
| public final T getEntity() { |
| return entity; |
| } |
| } |