private Object[] buildParamList(Invokable<?, ?> invokable, int indexOfParamToSetToNull) { ImmutableList<Parameter> params = invokable.getParameters(); Object[] args = new Object[params.size()]; for (int i = 0; i < args.length; i++) { Parameter param = params.get(i); if (i != indexOfParamToSetToNull) { args[i] = getDefaultValue(param.getType()); Assert.assertTrue( "Can't find or create a sample instance for type '" + param.getType() + "'; please provide one using NullPointerTester.setDefault()", args[i] != null || isNullable(param)); } } return args; }
/** * Tests null checks against the instance methods of the return values, if any. * * <p>Test fails if default value cannot be determined for a constructor or factory method * parameter, or if the constructor or factory method throws exception. * * @return this tester */ public FactoryMethodReturnValueTester testNulls() throws Exception { for (Invokable<?, ?> factory : getFactoriesToTest()) { Object instance = instantiate(factory); if (instance != null && packagesToTest.contains(Reflection.getPackageName(instance.getClass()))) { try { nullPointerTester.testAllPublicInstanceMethods(instance); } catch (AssertionError e) { AssertionError error = new AssertionFailedError( "Null check failed on return value of " + factory); error.initCause(e); throw error; } } } return this; }
/** * Runs serialization test on the return values of the static methods. * * <p>Test fails if default value cannot be determined for a constructor or factory method * parameter, or if the constructor or factory method throws exception. * * @return this tester */ public FactoryMethodReturnValueTester testSerializable() throws Exception { for (Invokable<?, ?> factory : getFactoriesToTest()) { Object instance = instantiate(factory); if (instance != null) { try { SerializableTester.reserialize(instance); } catch (RuntimeException e) { AssertionError error = new AssertionFailedError( "Serialization failed on return value of " + factory); error.initCause(e.getCause()); throw error; } } } return this; }
/** * Returns dummy factory arguments that are equal to {@code args} but may be different instances, * to be used to construct a second instance of the same equality group. */ private List<Object> generateEqualFactoryArguments( Invokable<?, ?> factory, List<Parameter> params, List<Object> args) throws ParameterNotInstantiableException, FactoryMethodReturnsNullException, InvocationTargetException, IllegalAccessException { List<Object> equalArgs = Lists.newArrayList(args); for (int i = 0; i < args.size(); i++) { Parameter param = params.get(i); Object arg = args.get(i); // Use new fresh value generator because 'args' were populated with new fresh generator each. // Two newFreshValueGenerator() instances should normally generate equal value sequence. Object shouldBeEqualArg = generateDummyArg(param, newFreshValueGenerator()); if (arg != shouldBeEqualArg && Objects.equal(arg, shouldBeEqualArg) && hashCodeInsensitiveToArgReference(factory, args, i, shouldBeEqualArg) && hashCodeInsensitiveToArgReference( factory, args, i, generateDummyArg(param, newFreshValueGenerator()))) { // If the implementation uses identityHashCode(), referential equality is // probably intended. So no point in using an equal-but-different factory argument. // We check twice to avoid confusion caused by accidental hash collision. equalArgs.set(i, shouldBeEqualArg); } } return equalArgs; }
private List<Object> getDummyArguments(Invokable<?, ?> invokable) throws ParameterNotInstantiableException { List<Object> args = Lists.newArrayList(); for (Parameter param : invokable.getParameters()) { if (param.isAnnotationPresent(Nullable.class)) { args.add(null); continue; } Object defaultValue = getDummyValue(param.getType()); if (defaultValue == null) { throw new ParameterNotInstantiableException(param); } args.add(defaultValue); } return args; }
private static @Nullable String invocationFailureReason(Invokable<?, ?> to, Invokable<?, ?> from) { final String reason = invocationFailureReason(methodType(to), methodType(from)); if(reason != null) return reason; thrownLoop: for(TypeToken<? extends Throwable> thrown : from.getExceptionTypes()) { final Class<?> thrownRaw = thrown.getRawType(); if(Error.class.isAssignableFrom(thrownRaw)) continue; if(RuntimeException.class.isAssignableFrom(thrownRaw)) continue ; for(TypeToken<? extends Throwable> caught : to.getExceptionTypes()) { if(caught.getRawType().isAssignableFrom(thrownRaw)) continue thrownLoop; } return "unhandled exception " + thrown.getRawType().getName(); } return null; }
@Override MethodHandle createHandle(Method rawProxyMethod, Invokable<T, ?> proxyMethod) throws ReflectiveOperationException { if(proxyMethod.getReturnType().getRawType().equals(void.class)) { if(proxyMethod.getParameters().size() == 1) { return lookup.findStaticSetter(targetType, proxyMethod.getName(), proxyMethod.getParameters().get(0).getType().getRawType()); } } else { if(proxyMethod.getParameters().isEmpty()) { return lookup.findStaticGetter(targetType, proxyMethod.getName(), proxyMethod.getReturnType().getRawType()); } } throw new MethodFormException(rawProxyMethod, "Field delegate method does not have a getter or setter signature"); }
private static void methods() { Methods ms1 = Scanner.paths("/io/ytcode/reflect/").scan().classes().methods(); Methods ms2 = ms1.filter( new Predicate<Method>() { @Override public boolean apply(Method m) { return Invokable.from(m).isPublic(); } }); System.out.println(ms2); Methods ms3 = ms1.modifiers(Modifier.PUBLIC, Modifier.STATIC); System.out.println(ms3); }
@Override protected void bind(Object target, String key, FixtureMap fixtureMap) { List<Method> candidates = findSetterCandidates(target, key); for (Method candidate : candidates) { ImmutableList<Parameter> paramTypes = Invokable.from(candidate).getParameters(); if (paramTypes.size() != 1) continue; TypeToken<?> paramType = paramTypes.get(0).getType(); try { Object candidateParam = getFixtureConverter().convert(fixtureMap, paramType); if (candidateParam != null) { candidate.invoke(target, candidateParam); return; } } catch (Exception e) { throw new FixtureMappingException(e); } } bindByField(target, key, fixtureMap); }
@Override protected void bind(Object target, String key, FixtureList fixtureList) { List<Method> candidates = findSetterCandidates(target, key); for (Method candidate :candidates) { try { ImmutableList<Parameter> paramTypes = Invokable.from(candidate).getParameters(); if (paramTypes.size() != 1) continue; TypeToken<?> paramType = paramTypes.get(0).getType(); Object candidateParam = getFixtureConverter().convert(fixtureList, paramType); if (candidateParam != null) { candidate.invoke(target, candidateParam); return; } } catch (Exception e) { throw new FixtureMappingException(e); } } bindByField(target, key, fixtureList); }
@Override protected void bind(Object target, String key, FixtureValue fixtureValue) { if (fixtureValue == null || fixtureValue.isNull()) return; List<Method> candidates = findSetterCandidates(target, key); for (Method candidate : candidates) { ImmutableList<Parameter> paramTypes = Invokable.from(candidate).getParameters(); if (paramTypes == null || paramTypes.size() != 1) continue; TypeToken<?> paramType = paramTypes.get(0).getType(); Object param = getFixtureConverter().convert(fixtureValue, paramType); if (param == null) continue; try { candidate.invoke(target, param); } catch (Exception e) { throw new FixtureMappingException(e); } } bindByField(target, key, fixtureValue); }
@Test public void testAllAuroraSchedulerManagerIfaceMethodsHaveAuthorizingParam() throws Exception { for (Method declaredMethod : AuroraSchedulerManager.Iface.class.getDeclaredMethods()) { Invokable<?, ?> invokable = Invokable.from(declaredMethod); Collection<Parameter> parameters = invokable.getParameters(); Invokable<?, ?> annotatedInvokable = Invokable.from( AnnotatedAuroraAdmin.class.getDeclaredMethod( invokable.getName(), FluentIterable.from(parameters) .transform(input -> input.getType().getRawType()) .toList() .toArray(new Class<?>[0]))); Collection<Parameter> annotatedParameters = Collections2.filter( annotatedInvokable.getParameters(), input -> input.getAnnotation(AuthorizingParam.class) != null); assertFalse( "Method " + invokable + " should have at least 1 " + AuthorizingParam.class.getName() + " annotation but none were found.", annotatedParameters.isEmpty()); } }
private void addExposedTypes(Invokable<?, ?> invokable, Class<?> cause) { addExposedTypes(invokable.getReturnType(), cause); for (Annotation annotation : invokable.getAnnotations()) { LOG.debug( "Adding exposed types from {}, which is an annotation on invokable {}", annotation, invokable); addExposedTypes(annotation.annotationType(), cause); } for (Parameter parameter : invokable.getParameters()) { LOG.debug( "Adding exposed types from {}, which is a parameter on invokable {}", parameter, invokable); addExposedTypes(parameter, cause); } for (TypeToken<?> exceptionType : invokable.getExceptionTypes()) { LOG.debug( "Adding exposed types from {}, which is an exception type on invokable {}", exceptionType, invokable); addExposedTypes(exceptionType, cause); } }
/** Returns an {@link Invokable} for each public methods or constructors of a type. */ private Set<Invokable> getExposedInvokables(TypeToken<?> type) { Set<Invokable> invokables = Sets.newHashSet(); for (Constructor constructor : type.getRawType().getConstructors()) { if (0 != (constructor.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED))) { invokables.add(type.constructor(constructor)); } } for (Method method : type.getRawType().getMethods()) { if (0 != (method.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED))) { invokables.add(type.method(method)); } } return invokables; }
private ImmutableList<EventualProvider<?>> introspectProviders() { ImmutableList.Builder<EventualProvider<?>> builder = ImmutableList.builder(); // FIXME handle method overriding? for (Class<?> t : type.getTypes().classes().rawTypes()) { if (t != Object.class) { for (Method m : t.getDeclaredMethods()) { if (m.isAnnotationPresent(Eventually.Provides.class)) { Errors methodErrors = errors.withSource(StackTraceElements.forMember(m)); Invokable<T, Object> invokable = type.method(m); if (eligibilityVerified(invokable, methodErrors)) { builder.add(providerFor(invokable, methodErrors)); } } } } } return builder.build(); }
private boolean eligibilityVerified(Invokable<T, Object> method, Errors errors) { List<TypeToken<?>> primitiveTypes = Lists.newArrayList(); for (Parameter parameter : method.getParameters()) { if (parameter.getType().isPrimitive()) { primitiveTypes.add(parameter.getType()); } } if (method.getReturnType().isPrimitive() && !isVoid(method)) { primitiveTypes.add(method.getReturnType()); } if (!primitiveTypes.isEmpty()) { errors.addMessage("Incompartible eventual provider method '%s'" + "\n\tSignature has primitive types: %s." + " Please use boxed types instead", method.getName(), Joiner.on(", ").join(primitiveTypes)); } return primitiveTypes.isEmpty(); }
EventualProvider( Invokable<T, ?> method, boolean exposedBinding, List<Dependency<ListenableFuture<?>>> dependencies, Key<ListenableFuture<?>> bindingKey, @Nullable Class<? extends Annotation> scopeAnnotation, Object source) { this.method = method; this.source = source; this.exposedBinding = exposedBinding; this.bindingKey = bindingKey; this.scopeAnnotation = scopeAnnotation; this.dependencies = ImmutableList.copyOf(dependencies); this.dependencySet = ImmutableSet.<Dependency<?>>builder() .addAll(dependencies) .add(Dependency.get(Key.get(Injector.class))) .add(Dependency.get(Key.get(type.getRawType()))) .build(); }
private static StackTraceElement[] trimStackTrace(StackTraceElement[] stackTrace) { String[] trimmedPrefixes = { Futures.class.getPackage().getName(), Invokable.class.getPackage().getName(), Providers.class.getName() }; List<StackTraceElement> list = Lists.newArrayListWithExpectedSize(stackTrace.length); stackLines: for (int i = 0; i < stackTrace.length; i++) { StackTraceElement element = stackTrace[i]; for (int j = 0; j < trimmedPrefixes.length; j++) { String prefix = trimmedPrefixes[j]; if (element.getClassName().startsWith(prefix)) { continue stackLines; } } list.add(element); } return list.toArray(new StackTraceElement[list.size()]); }
private static <T, R> void assertValidReprMethods(Set<Invokable<T, ?>> methods, Class<R> returnType) { Set<Invokable<T, ?>> invalidMethods = new HashSet<>(); for (Invokable<T, ?> method : methods) { if ((!method.getReturnType().isSubtypeOf(returnType)) // || (method.getParameters().size() != 1) // || !REPR_METHOD_NAME.equals(method.getName())) { invalidMethods.add(method); } } if (!invalidMethods.isEmpty()) { throw new IllegalArgumentException( "All public methods in a representer class " + "must fulfill the following contract:\n" // + "*) name=='" + REPR_METHOD_NAME + "'\n" // + "*) one single parameter\n" // + "*) All the same return type (" + returnType + " in this case)\n" // + "The following methods do not fulfill this contract: " + invalidMethods); } }
@Override public R apply(T t, Function<Object, R> callback) { Objects.requireNonNull(callback, "recursionCallback must not be null."); CT instanceToDispatchTo = newInstance(callback); for (Entry<Class<?>, Invokable<CT, R>> entry : this.methods.entrySet()) { Class<?> parameterType = entry.getKey(); if (parameterType.isInstance(t)) { Invokable<CT, R> invokable = entry.getValue(); try { R result = invokable.invoke(instanceToDispatchTo, t); if (result != null) { return result; } } catch (Exception e) { LOGGER.warn("Could not invoke {}.", invokable, e); } } } return null; }
/** * Tests null checks against the instance methods of the return values, if any. * * <p>Test fails if default value cannot be determined for a constructor or factory method * parameter, or if the constructor or factory method throws exception. * * @return this tester */ public FactoryMethodReturnValueTester testNulls() throws Exception { for (Invokable<?, ?> factory : getFactoriesToTest()) { Object instance = instantiate(factory); if (instance != null && packagesToTest.contains(Reflection.getPackageName(instance.getClass()))) { try { nullPointerTester.testAllPublicInstanceMethods(instance); } catch (AssertionError e) { AssertionError error = new AssertionFailedError("Null check failed on return value of " + factory); error.initCause(e); throw error; } } } return this; }
/** * Runs serialization test on the return values of the static methods. * * <p>Test fails if default value cannot be determined for a constructor or factory method * parameter, or if the constructor or factory method throws exception. * * @return this tester */ public FactoryMethodReturnValueTester testSerializable() throws Exception { for (Invokable<?, ?> factory : getFactoriesToTest()) { Object instance = instantiate(factory); if (instance != null) { try { SerializableTester.reserialize(instance); } catch (RuntimeException e) { AssertionError error = new AssertionFailedError("Serialization failed on return value of " + factory); error.initCause(e.getCause()); throw error; } } } return this; }
private ImmutableList<Invokable<?, ?>> getFactoriesToTest() { ImmutableList.Builder<Invokable<?, ?>> builder = ImmutableList.builder(); for (Invokable<?, ?> factory : factories) { if (returnTypeToTest.isAssignableFrom(factory.getReturnType().getRawType())) { builder.add(factory); } } ImmutableList<Invokable<?, ?>> factoriesToTest = builder.build(); Assert.assertFalse( "No " + factoryMethodsDescription + " that return " + returnTypeToTest.getName() + " or subtype are found in " + declaringClass + ".", factoriesToTest.isEmpty()); return factoriesToTest; }
private List<Object> getDummyArguments(Invokable<?, ?> invokable) throws ParameterNotInstantiableException { List<Object> args = Lists.newArrayList(); for (Parameter param : invokable.getParameters()) { if (isNullable(param)) { args.add(null); continue; } Object defaultValue = getDummyValue(param.getType()); if (defaultValue == null) { throw new ParameterNotInstantiableException(param); } args.add(defaultValue); } return args; }