/* * 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; } } }