/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.blueprint.container;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.osgi.service.blueprint.container.ReifiedType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* Adaptor factory between Spring type descriptor and OSGi 4.2 Reified type.
*
* @author Costin Leau
*/
class TypeFactory {
private static final GenericsReifiedType OBJECT = new GenericsReifiedType(Object.class);
private static class GenericsReifiedType extends ReifiedType {
private final List<ReifiedType> arguments;
private final int size;
GenericsReifiedType(Class<?> clazz) {
this(TypeDescriptor.valueOf(clazz));
}
GenericsReifiedType(TypeDescriptor descriptor) {
super((descriptor == null) ? Object.class: ClassUtils.resolvePrimitiveIfNecessary(descriptor.getType()));
arguments = getArguments(descriptor);
size = arguments.size();
}
@Override
public ReifiedType getActualTypeArgument(int i) {
if (i >= 0 && i < size) {
return arguments.get(i);
}
if (i == 0) {
return super.getActualTypeArgument(0);
}
throw new IllegalArgumentException("Invalid argument index given " + i);
}
@Override
public int size() {
return size;
}
}
static ReifiedType getType(TypeDescriptor targetType) {
return new GenericsReifiedType(targetType);
}
private static List<ReifiedType> getArguments(TypeDescriptor type) {
List<ReifiedType> arguments;
if (type == null) {
return Collections.emptyList();
}
// is it a collection or an array
if (type.isCollection() || type.isArray()) {
arguments = new ArrayList<ReifiedType>(1);
Class<?> elementType = type.getElementTypeDescriptor() == null ? null : type.getElementTypeDescriptor().getType();
arguments.add(elementType != null ? new GenericsReifiedType(elementType) : OBJECT);
return arguments;
}
// is it a map
if (type.isMap()) {
arguments = new ArrayList<ReifiedType>(2);
Class<?> keyType = type.getMapKeyTypeDescriptor() == null ? null : type.getMapKeyTypeDescriptor().getType();
arguments.add(keyType != null ? new GenericsReifiedType(keyType) : OBJECT);
Class<?> valueType = type.getMapValueTypeDescriptor() == null ? null : type.getMapValueTypeDescriptor().getType();
arguments.add(valueType != null ? new GenericsReifiedType(valueType) : OBJECT);
return arguments;
}
// some other generic type
if (type.getType().getTypeParameters() != null) {
arguments = new ArrayList<ReifiedType>(1);
for (TypeVariable tv : type.getType().getTypeParameters()) {
ReifiedType rType = getReifiedType(tv);
arguments.add(rType);
}
return arguments;
}
return Collections.emptyList();
}
private static ReifiedType getReifiedType(Type targetType) {
if (targetType instanceof Class) {
if (Object.class.equals(targetType)) {
return OBJECT;
}
return new GenericsReifiedType((Class<?>) targetType);
}
if (targetType instanceof ParameterizedType) {
Type ata = ((ParameterizedType) targetType).getActualTypeArguments()[0];
return getReifiedType(ata);
}
if (targetType instanceof WildcardType) {
WildcardType wt = (WildcardType) targetType;
Type[] lowerBounds = wt.getLowerBounds();
if (ObjectUtils.isEmpty(lowerBounds)) {
// there's always an upper bound (Object)
Type upperBound = wt.getUpperBounds()[0];
return getReifiedType(upperBound);
}
return getReifiedType(lowerBounds[0]);
}
if (targetType instanceof TypeVariable) {
Type[] bounds = ((TypeVariable<?>) targetType).getBounds();
return getReifiedType(bounds[0]);
}
if (targetType instanceof GenericArrayType) {
return getReifiedType(((GenericArrayType) targetType).getGenericComponentType());
}
throw new IllegalArgumentException("Unknown type " + targetType.getClass());
}
}