/* * Copyright 2008-2017 the original author or authors. * * 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 org.codehaus.griffon.compile.core; import java.lang.reflect.Modifier; /** * @author Andres Almiray */ public class MethodDescriptor { private static final TypeParam[] EMPTY_PARAMETERS = new TypeParam[0]; private static final Type[] EMPTY_TYPES = new Type[0]; private static final Type NO_BOUND = new Type("_"); public static class Type { public final String type; public final Type[] parameters; public final Type[] annotations; public final int dimensions; public String signature; public Type(String type) { this(EMPTY_TYPES, type, 0, EMPTY_TYPES); } public Type(String type, int dimensions) { this(EMPTY_TYPES, type, dimensions, EMPTY_TYPES); } public Type(String type, Type[] parameters) { this(EMPTY_TYPES, type, 0, parameters); } public Type(String type, int dimensions, Type[] parameters) { this(EMPTY_TYPES, type, dimensions, parameters); } public Type(Type[] annotations, String type) { this(annotations, type, 0, EMPTY_TYPES); } public Type(Type[] annotations, String type, int dimensions) { this(annotations, type, dimensions, EMPTY_TYPES); } public Type(Type[] annotations, String type, Type[] parameters) { this(annotations, type, 0, parameters); } public Type(Type[] annotations, String type, int dimensions, Type[] parameters) { this.type = type; this.dimensions = dimensions; this.parameters = parameters != null ? parameters : EMPTY_TYPES; this.annotations = annotations != null ? annotations : EMPTY_TYPES; } public String signature() { if (signature == null) { signature = createTypeSignature(); } return signature; } protected String createTypeSignature() { StringBuilder b = new StringBuilder(""); for (Type annotation : annotations) { b.append("@") .append(annotation.signature()) .append(" "); } b.append(type); if (parameters.length > 0) { b.append("<"); for (int i = 0; i < parameters.length; i++) { b.append(parameters[i].signature()); if (i < parameters.length - 1) b.append(", "); } b.append(">"); } for (int d = 0; d < dimensions; d++) { b.append("[]"); } return b.toString(); } public String toString() { return signature(); } } public static class Wildcard extends Type { public static final String EXTENDS = "extends"; public static final String SUPER = "super"; public static final String NONE = "_"; public final String bound; public Wildcard() { this(NONE, EMPTY_TYPES); } public Wildcard(Type[] parameters) { this(EXTENDS, parameters); } public Wildcard(String bound, Type[] parameters) { super("?", parameters); this.bound = bound; } public boolean isExtends() { return EXTENDS.equals(bound); } public boolean isSuper() { return SUPER.equals(bound); } protected String createTypeSignature() { StringBuilder b = new StringBuilder(type); if (parameters.length > 0) { b.append(" ").append(bound).append(" "); for (int i = 0; i < parameters.length; i++) { b.append(parameters[i].signature()); if (i < parameters.length - 1) b.append(", "); } } return b.toString(); } } public static class TypeParam { public final String type; public final Type bound; public final String signature; public TypeParam(String type) { this(type, NO_BOUND); } public TypeParam(String type, Type bound) { this.type = type; this.bound = bound != null ? bound : NO_BOUND; this.signature = createTypeParamSignature(); } public boolean isBound() { return bound != NO_BOUND; } private String createTypeParamSignature() { StringBuilder b = new StringBuilder(type); if (bound != NO_BOUND) { b.append(" extends ").append(bound.signature()); } return b.toString(); } public String toString() { return signature; } } public final int modifiers; public final String methodName; public final Type returnType; public final TypeParam[] typeParameters; public final Type[] annotations; public final Type[] exceptions; public final Type[] arguments; public final String signature; public MethodDescriptor(Type returnType, TypeParam[] typeParameters, String methodName, Type[] arguments, Type[] exceptions) { this(Modifier.PUBLIC, returnType, typeParameters, methodName, arguments, exceptions, EMPTY_TYPES); } public MethodDescriptor(Type returnType, TypeParam[] typeParameters, String methodName, Type[] arguments, Type[] exceptions, Type[] annotations) { this(Modifier.PUBLIC, returnType, typeParameters, methodName, arguments, exceptions, annotations); } public MethodDescriptor(int modifiers, Type returnType, TypeParam[] typeParameters, String methodName, Type[] arguments, Type[] exceptions) { this(modifiers, returnType, typeParameters, methodName, arguments, exceptions, EMPTY_TYPES); } public MethodDescriptor(int modifiers, Type returnType, TypeParam[] typeParameters, String methodName, Type[] arguments, Type[] exceptions, Type[] annotations) { this.modifiers = modifiers; this.returnType = returnType; this.methodName = methodName; this.typeParameters = typeParameters != null ? typeParameters : EMPTY_PARAMETERS; this.arguments = arguments != null ? arguments : EMPTY_TYPES; this.exceptions = exceptions != null ? exceptions : EMPTY_TYPES; this.annotations = annotations != null ? annotations : EMPTY_TYPES; this.signature = createMethodSignature(); } public String toString() { return signature; } private String createMethodSignature() { StringBuilder b = new StringBuilder(); for (Type annotation : annotations) { b.append("@") .append(annotation.signature()) .append(" "); } b.append(Modifier.toString(modifiers)).append(" "); if (typeParameters.length > 0) { b.append("<"); for (int i = 0; i < typeParameters.length; i++) { b.append(typeParameters[i].signature); if (i < typeParameters.length - 1) b.append(", "); } b.append("> "); } b.append(returnType.signature()) .append(" ") .append(methodName) .append("("); if (arguments.length > 0) { for (int i = 0; i < arguments.length; i++) { b.append(arguments[i].signature()) .append(" arg") .append(i); if (i < arguments.length - 1) b.append(", "); } } b.append(")"); if (exceptions.length > 0) { b.append(" throws "); for (int i = 0; i < exceptions.length; i++) { b.append(exceptions[i].signature()); if (i < exceptions.length - 1) b.append(", "); } } return b.toString(); } public static Wildcard wildcard(String... types) { return new Wildcard(types(types)); } public static Wildcard wildcardWithParams(Type... types) { return new Wildcard(types); } public static Type annotation(String type) { return new Type(type); } public static Type[] annotations(String... types) { Type[] annotations = new Type[types.length]; for (int i = 0; i < types.length; i++) { annotations[i] = annotation(types[i]); } return annotations; } public static Type type(String type, String... types) { return new Type(type, types(types)); } public static Type type(String type, int dimensions, String... types) { return new Type(type, dimensions, types(types)); } public static Type annotatedType(Type[] annotations, String type, String... types) { return new Type(annotations, type, types(types)); } public static Type annotatedType(Type[] annotations, String type, int dimensions, String... types) { return new Type(annotations, type, dimensions, types(types)); } public static Type typeWithParams(String type, Type... types) { return new Type(type, types); } public static Type typeWithParams(String type, int dimensions, Type... types) { return new Type(type, dimensions, types); } public static Type typeWithParams(Type[] annotations, String type, Type... types) { return new Type(annotations, type, types); } public static Type typeWithParams(Type[] annotations, String type, int dimensions, Type... types) { return new Type(annotations, type, dimensions, types); } public static TypeParam[] typeParams(String... typeParameters) { TypeParam[] params = new TypeParam[typeParameters.length]; for (int i = 0; i < typeParameters.length; i++) { params[i] = new TypeParam(typeParameters[i]); } return params; } public static TypeParam[] typeParams(TypeParam... typeParameters) { return typeParameters; } public static TypeParam typeParam(String type) { return new TypeParam(type); } public static TypeParam typeParam(String type, String bound) { return new TypeParam(type, type(bound)); } public static TypeParam typeParam(String type, Type bound) { return new TypeParam(type, bound); } public static Type[] types(String... types) { Type[] t = new Type[types.length]; for (int i = 0; i < types.length; i++) { t[i] = type(types[i]); } return t; } public static Type[] types(Type... types) { return types; } public static Type[] args(Type... types) { return types; } public static Type[] throwing(Type... types) { return types; } public static MethodDescriptor method(Type type, TypeParam[] typeParameters, String methodName, Type[] args) { return new MethodDescriptor(type, typeParameters, methodName, args, EMPTY_TYPES); } public static MethodDescriptor method(Type type, TypeParam[] typeParameters, String methodName) { return new MethodDescriptor(type, typeParameters, methodName, EMPTY_TYPES, EMPTY_TYPES); } public static MethodDescriptor method(Type type, String methodName, Type[] args) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, args, EMPTY_TYPES); } public static MethodDescriptor method(Type type, String methodName) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, EMPTY_TYPES, EMPTY_TYPES); } public static MethodDescriptor method(Type type, TypeParam[] typeParameters, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(type, typeParameters, methodName, args, exceptions); } public static MethodDescriptor method(Type type, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, args, exceptions); } public static MethodDescriptor method(int modifiers, Type type, TypeParam[] typeParameters, String methodName, Type[] args) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, args, EMPTY_TYPES); } public static MethodDescriptor method(int modifiers, Type type, TypeParam[] typeParameters, String methodName) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, EMPTY_TYPES, EMPTY_TYPES); } public static MethodDescriptor method(int modifiers, Type type, String methodName, Type[] args) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, args, EMPTY_TYPES); } public static MethodDescriptor method(int modifiers, Type type, String methodName) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, EMPTY_TYPES, EMPTY_TYPES); } public static MethodDescriptor method(int modifiers, Type type, TypeParam[] typeParameters, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, args, exceptions); } public static MethodDescriptor method(int modifiers, Type type, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, args, exceptions); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, TypeParam[] typeParameters, String methodName, Type[] args) { return new MethodDescriptor(type, typeParameters, methodName, args, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, TypeParam[] typeParameters, String methodName) { return new MethodDescriptor(type, typeParameters, methodName, EMPTY_TYPES, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, String methodName, Type[] args) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, args, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, String methodName) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, EMPTY_TYPES, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, TypeParam[] typeParameters, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(type, typeParameters, methodName, args, exceptions, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, Type type, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(type, EMPTY_PARAMETERS, methodName, args, exceptions, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, TypeParam[] typeParameters, String methodName, Type[] args) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, args, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, TypeParam[] typeParameters, String methodName) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, EMPTY_TYPES, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, String methodName, Type[] args) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, args, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, String methodName) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, EMPTY_TYPES, EMPTY_TYPES, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, TypeParam[] typeParameters, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(modifiers, type, typeParameters, methodName, args, exceptions, annotations); } public static MethodDescriptor annotatedMethod(Type[] annotations, int modifiers, Type type, String methodName, Type[] args, Type[] exceptions) { return new MethodDescriptor(modifiers, type, EMPTY_PARAMETERS, methodName, args, exceptions, annotations); } }