/* * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team) * * 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. */ package com.querydsl.codegen; import com.google.common.base.Objects; import com.mysema.codegen.model.SimpleType; import com.mysema.codegen.model.Type; import com.mysema.codegen.model.TypeExtends; import com.mysema.codegen.model.TypeSuper; /** * {@code TypeResolver} provides type resolving functionality for resolving generic type variables to * concrete types * * @author tiwe * */ final class TypeResolver { /** * Resolve type declared in declaringType for context * * @param type type to be resolved * @param declaringType declaration context of type * @param context target context of type * @return resolved type */ public static Type resolve(Type type, Type declaringType, EntityType context) { Type resolved = unwrap(type); String varName = getVarName(resolved); if (varName != null) { resolved = resolveVar(resolved, varName, declaringType, context); } else if (!resolved.getParameters().isEmpty()) { resolved = resolveWithParameters(resolved, declaringType, context); } // rewrap entity type if (type instanceof EntityType) { if (!unwrap(type).equals(resolved)) { resolved = new EntityType(resolved, ((EntityType) type).getSuperTypes()); } else { // reset to original type resolved = type; } } return resolved; } private static Type resolveVar(Type resolved, String varName, Type declaringType, EntityType context) { // get parameter index of var in declaring type int index = -1; for (int i = 0; i < declaringType.getParameters().size(); i++) { Type param = unwrap(declaringType.getParameters().get(i)); if (Objects.equal(getVarName(param), varName)) { index = i; } } if (index == -1) { throw new IllegalStateException("Did not find type " + varName + " in " + declaringType + " for " + context); } Supertype type = context.getSuperType(); while (!type.getEntityType().equals(declaringType)) { type = type.getEntityType().getSuperType(); } if (!type.getType().getParameters().isEmpty()) { return type.getType().getParameters().get(index); } else { // raw type return resolved; } } private static Type resolveWithParameters(Type type, Type declaringType, EntityType context) { Type[] params = new Type[type.getParameters().size()]; boolean transformed = false; for (int i = 0; i < type.getParameters().size(); i++) { Type param = type.getParameters().get(i); if (param != null && !param.getFullName().equals(type.getFullName())) { params[i] = resolve(param, declaringType, context); if (!params[i].equals(param)) { transformed = true; } } } if (transformed) { return new SimpleType(type, params); } else { return type; } } private static String getVarName(Type type) { if (type instanceof TypeExtends) { return ((TypeExtends) type).getVarName(); } else if (type instanceof TypeSuper) { return ((TypeSuper) type).getVarName(); } else { return null; } } private static Type unwrap(Type type) { if (type instanceof EntityType) { return ((EntityType) type).getInnerType(); } else { return type; } } private TypeResolver() { } }