/* * -\-\- * DataEnum * -- * Copyright (c) 2017 Spotify AB * -- * 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.spotify.dataenum.processor.generator.data; import static com.spotify.dataenum.processor.generator.data.OutputSpecFactory.isSpecClassName; import static com.spotify.dataenum.processor.generator.data.OutputSpecFactory.toOutputClassName; import com.spotify.dataenum.processor.data.OutputValue; import com.spotify.dataenum.processor.data.Parameter; import com.spotify.dataenum.processor.data.Spec; import com.spotify.dataenum.processor.data.Value; import com.spotify.dataenum.processor.parser.ParserException; import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; final class OutputValueFactory { private OutputValueFactory() {} static OutputValue create(Value value, ClassName specOutputClass, Spec spec) throws ParserException { ClassName outputClass = specOutputClass.nestedClass(value.name()); Iterable<TypeVariableName> typeVariables = getTypeVariables(value, spec.typeVariables()); List<Parameter> parameters = new ArrayList<>(); for (Parameter parameter : value.parameters()) { parameters.add(parameterWithoutDataEnumSuffix(parameter)); } return new OutputValue( outputClass, value.name(), value.javadoc(), parameters, typeVariables, value.annotations()); } private static Parameter parameterWithoutDataEnumSuffix(Parameter parameter) throws ParserException { return new Parameter( parameter.name(), typeWithoutDataEnumSuffixes(parameter.type()), parameter.canBeNull(), parameter.redacted(), parameter.isEnum()); } private static TypeName typeWithoutDataEnumSuffixes(TypeName typeName) throws ParserException { if (typeName instanceof ParameterizedTypeName) { ParameterizedTypeName paramTypeName = (ParameterizedTypeName) typeName; ClassName outputClassName; if (isSpecClassName(paramTypeName.rawType)) { outputClassName = toOutputClassName(paramTypeName.rawType); } else { outputClassName = paramTypeName.rawType; } TypeName[] typeArgumentsArr = new TypeName[paramTypeName.typeArguments.size()]; for (int i = 0; i < typeArgumentsArr.length; i++) { typeArgumentsArr[i] = typeWithoutDataEnumSuffixes(paramTypeName.typeArguments.get(i)); } return ParameterizedTypeName.get(outputClassName, typeArgumentsArr); } if (typeName instanceof ClassName) { ClassName className = (ClassName) typeName; if (isSpecClassName(className)) { return toOutputClassName(className); } return className; } return typeName; } private static Iterable<TypeVariableName> getTypeVariables( Value value, Iterable<TypeVariableName> typeVariables) { Set<TypeVariableName> output = new LinkedHashSet<>(); for (TypeVariableName typeVariable : typeVariables) { for (Parameter parameter : value.parameters()) { if (typeNeedsTypeVariable(parameter.type(), typeVariable)) { output.add(typeVariable); } } } return output; } private static boolean typeNeedsTypeVariable(TypeName type, TypeVariableName typeVariable) { if (typeVariable.equals(type)) { return true; } if (type instanceof ParameterizedTypeName) { ParameterizedTypeName parameterized = ((ParameterizedTypeName) type); for (TypeName typeArgument : parameterized.typeArguments) { if (typeVariable.equals(typeArgument)) { return true; } if (typeNeedsTypeVariable(typeArgument, typeVariable)) { return true; } } } if (type instanceof ArrayTypeName) { ArrayTypeName arrayType = (ArrayTypeName) type; if (typeVariable.equals(arrayType.componentType)) { return true; } } return false; } }