/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.isis.core.metamodel.facets.actcoll.typeof;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import org.apache.isis.applib.annotation.Programmatic;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facets.SingleClassValueFacet;
import org.apache.isis.core.metamodel.specloader.CollectionUtils;
import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
/**
* The type of the collection or the action.
*
* <p>
* In the standard Apache Isis Programming Model, corresponds to annotating the
* collection's accessor or the action's invoker method with the
* <tt>@TypeOf</tt> annotation.
*/
public interface TypeOfFacet extends SingleClassValueFacet {
public static class Util {
private Util(){}
@Programmatic
public static TypeOfFacet inferFromGenericReturnType(
final Class<?> cls,
final Method method,
final FacetHolder holder,
final SpecificationLoader specificationLoader) {
final Class<?> methodReturnType = method.getReturnType();
if (!CollectionUtils.isCollectionType(methodReturnType)) {
return null;
}
final Type type = method.getGenericReturnType();
if (!(type instanceof ParameterizedType)) {
return null;
}
final ParameterizedType methodParameterizedType = (ParameterizedType) type;
final Type[] methodActualTypeArguments = methodParameterizedType.getActualTypeArguments();
if (methodActualTypeArguments.length == 0) {
return null;
}
final Object methodActualTypeArgument = methodActualTypeArguments[0];
if (methodActualTypeArgument instanceof Class) {
final Class<?> actualType = (Class<?>) methodActualTypeArgument;
return new TypeOfFacetInferredFromGenerics(actualType, holder, specificationLoader);
}
if (methodActualTypeArgument instanceof TypeVariable) {
final TypeVariable<?> methodTypeVariable = (TypeVariable<?>) methodActualTypeArgument;
final GenericDeclaration methodGenericClassDeclaration = methodTypeVariable.getGenericDeclaration();
// try to match up with the actual type argument of the generic superclass.
final Type genericSuperclass = cls.getGenericSuperclass();
if(genericSuperclass instanceof ParameterizedType) {
final ParameterizedType parameterizedTypeOfSuperclass = (ParameterizedType)genericSuperclass;
if(parameterizedTypeOfSuperclass.getRawType() == methodGenericClassDeclaration) {
final Type[] genericSuperClassActualTypeArguments = parameterizedTypeOfSuperclass.getActualTypeArguments();
// simplification: if there's just one, then use it.
if(methodActualTypeArguments.length == 1) {
final Type actualType = genericSuperClassActualTypeArguments[0];
if(actualType instanceof Class) {
// just being safe
final Class<?> actualCls = (Class<?>) actualType;
return new TypeOfFacetInferredFromGenerics(actualCls, holder, specificationLoader);
}
}
}
}
// otherwise, what to do?
}
return null;
}
@Programmatic
public static TypeOfFacet inferFromArrayType(
final FacetHolder holder,
final Class<?> type,
final SpecificationLoader specificationLoader) {
final Class<?> componentType = CollectionUtils.inferFromArrayType(type);
return componentType != null
? new TypeOfFacetInferredFromArray(componentType, holder, specificationLoader)
: null;
}
@Programmatic
public static TypeOfFacet inferFromGenericParamType(
final FacetHolder holder,
final Class<?> parameterType,
final Type genericParameterType,
final SpecificationLoader specificationLoader) {
final Class<?> actualType = CollectionUtils.inferFromGenericParamType(parameterType, genericParameterType);
return actualType != null
? new TypeOfFacetInferredFromGenerics(actualType, holder, specificationLoader)
: null;
}
}
}