diff --git a/build.gradle b/build.gradle index a3c7850..1ab0a4c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'me.davidsargent' -version '0.1' +version '0.1.2' apply plugin: 'java' apply plugin: 'application' @@ -17,6 +17,11 @@ jar { } } +tasks.withType(AbstractArchiveTask) { + preserveFileTimestamps = false + reproducibleFileOrder = true +} + dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile 'org.jetbrains:annotations:15.0' diff --git a/src/main/java/me/davidsargent/stubjars/components/JarMethod.java b/src/main/java/me/davidsargent/stubjars/components/JarMethod.java index 7e08031..cc27c71 100644 --- a/src/main/java/me/davidsargent/stubjars/components/JarMethod.java +++ b/src/main/java/me/davidsargent/stubjars/components/JarMethod.java @@ -13,15 +13,15 @@ package me.davidsargent.stubjars.components; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.*; import java.util.Arrays; import java.util.Set; public class JarMethod extends JarModifers { private final Method method; + private String[] cachedParameters; public JarMethod(Method method) { this.method = method; @@ -40,11 +40,32 @@ public Class returnType() { return method.getReturnType(); } + public boolean isVarArg() { + return method.isVarArgs(); + } + + @NotNull public String[] parameters() { + if (cachedParameters != null) return cachedParameters; Parameter[] parameters = method.getParameters(); - return Arrays.stream(parameters) + String[] stringifiedParameters = Arrays.stream(parameters) .map(parameter -> JarType.toString(parameter.getParameterizedType()) + " " + parameter.getName()) .toArray(String[]::new); + + if (method.isVarArgs()) { + Parameter varArgsParameter = parameters[parameters.length - 1]; + Type parameterizedType = varArgsParameter.getParameterizedType(); + if (JarType.isArray(parameterizedType)) { + if (parameterizedType instanceof GenericArrayType) { + stringifiedParameters[parameters.length - 1] = JarType.toString(((GenericArrayType) parameterizedType).getGenericComponentType()) + "... " + varArgsParameter.getName(); + } else if (parameterizedType instanceof Class) { + stringifiedParameters[parameters.length - 1] = JarType.toString(((Class) parameterizedType).getComponentType()) + "... " + varArgsParameter.getName(); + } + } + } + + cachedParameters = stringifiedParameters; + return stringifiedParameters; } public boolean isSynthetic() { @@ -95,4 +116,12 @@ public boolean hasDefaultValue() { public Object defaultValue() { return method.getDefaultValue(); } + + public Type[] throwsTypes() { + return method.getGenericExceptionTypes(); + } + + public boolean requiresThrowsSignature() { + return throwsTypes().length > 0; + } } diff --git a/src/main/java/me/davidsargent/stubjars/components/JarType.java b/src/main/java/me/davidsargent/stubjars/components/JarType.java index 7584738..3d9a32a 100644 --- a/src/main/java/me/davidsargent/stubjars/components/JarType.java +++ b/src/main/java/me/davidsargent/stubjars/components/JarType.java @@ -130,4 +130,8 @@ public static String toString(@NotNull Type type, boolean keepSimple, @Nullable // debug return type.toString(); throw new UnsupportedOperationException(type.getClass().getName()); } + + public static boolean isArray(Type parameterizedType) { + return parameterizedType instanceof GenericArrayType || (parameterizedType instanceof Class && ((Class) parameterizedType).isArray()); + } } diff --git a/src/main/java/me/davidsargent/stubjars/components/writer/JavaClassWriter.java b/src/main/java/me/davidsargent/stubjars/components/writer/JavaClassWriter.java index 9addfb3..dc1a497 100644 --- a/src/main/java/me/davidsargent/stubjars/components/writer/JavaClassWriter.java +++ b/src/main/java/me/davidsargent/stubjars/components/writer/JavaClassWriter.java @@ -294,7 +294,7 @@ private static String compileMethods(@NotNull final JarClass klazz, boolean i final String returnTypeS = JarType.toString(method.genericReturnType()); final String nameS = method.name(); final String parametersS = Utils.arrayToCommaSeparatedList(method.parameters(), x -> x); - + final String throwsS = method.requiresThrowsSignature() ? " throws " + Utils.arrayToCommaSeparatedList(method.throwsTypes(), JarType::toString) : ""; final String genericS; TypeVariable[] typeParameters = method.typeParameters(); genericS = convertTypeParametersToString(typeParameters); @@ -310,7 +310,7 @@ private static String compileMethods(@NotNull final JarClass klazz, boolean i // Finally, put all of the pieces together compiledMethods.append('\n').append(security).append(finalS).append(staticS).append(abstractS).append(genericS).append(returnTypeS).append(" ") - .append(nameS).append('(').append(parametersS).append(')'); + .append(nameS).append('(').append(parametersS).append(')').append(throwsS); if (klazz.isAnnotation() && method.hasDefaultValue()) { compiledMethods.append(" default ").append(defaultValueForType(method.defaultValue().getClass(), true)).append(";"); } else if (method.isAbstract() || (klazz.isInterface() && !method.isStatic())) {