Java tutorial
package com.lexicalscope.fluentreflection; /* * Copyright 2011 Tim Wood * * 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. */ import static ch.lambdaj.Lambda.*; import static com.lexicalscope.fluentreflection.FluentReflection.object; import static com.lexicalscope.fluentreflection.ReflectionMatchers.compatibleWith; import static com.lexicalscope.fluentreflection.Visibility.visibilityFromModifiers; import static java.lang.String.format; import static java.lang.System.arraycopy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.TypeVariable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hamcrest.Matcher; import com.google.inject.TypeLiteral; final class FluentMethodImpl extends AbstractFluentAnnotated implements FluentMethod { private final ReflectedTypeFactory reflectedTypeFactory; private final TypeLiteral<?> typeLiteral; private final Method method; public FluentMethodImpl(final ReflectedTypeFactory reflectedTypeFactory, final TypeLiteral<?> typeLiteral, final Method method) { super(reflectedTypeFactory, method); this.reflectedTypeFactory = reflectedTypeFactory; this.typeLiteral = typeLiteral; this.method = method; } @Override public String name() { return method.getName(); } @Override public List<FluentClass<?>> args() { final List<FluentClass<?>> result = new ArrayList<FluentClass<?>>(); result.addAll(convert(typeLiteral.getParameterTypes(method), new ConvertTypeLiteralToReflectedType(reflectedTypeFactory))); return result; } @Override public int indexOfArg(final Matcher<? super FluentClass<?>> matcher) { final List<FluentClass<?>> args = args(); for (int i = 0; i < args.size(); i++) { if (matcher.matches(args.get(i))) { return i; } } throw new IndexOutOfBoundsException("No argment matching " + matcher); } @Override public int argCount() { return method.getParameterTypes().length; } @Override public FluentClass<?> declarer() { return reflectedTypeFactory.reflect(typeLiteral); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public FluentObject<?> call(final Object... args) { final Object object = callRaw(args); if (object == null && typeLiteral.getReturnType(method) != null) { return reflectedTypeFactory.reflect(typeLiteral.getReturnType(method), null); } return reflectedTypeFactory.reflect((Class) object.getClass(), object); } private Object callRaw(final Object... args) { if (isStatic()) { return invokeMethod(null, args); } else { if (args.length < 1) { throw new IllegalArgumentException( "target instance must be specified as first argument when calling " + method); } else if (args[0] == null) { return null; } final Object[] remainingArguments = new Object[args.length - 1]; arraycopy(args, 1, remainingArguments, 0, args.length - 1); return invokeMethod(args[0], remainingArguments); } } private Object invokeMethod(final Object instance, final Object[] arguments) { try { if (!method.isAccessible()) { method.setAccessible(true); } return method.invoke(instance, arguments); } catch (final IllegalArgumentException e) { throw new IllegalArgumentRuntimeException(e, method, instance, arguments); } catch (final IllegalAccessException e) { throw new IllegalAccessRuntimeException(e, method); } catch (final InvocationTargetException e) { throw new InvocationTargetRuntimeException(e, method); } } @Override public boolean isStatic() { return Modifier.isStatic(method.getModifiers()); } @Override public boolean isFinal() { return Modifier.isFinal(method.getModifiers()); } @Override public FluentClass<?> type() { final TypeLiteral<?> returnType = typeLiteral.getReturnType(method); if (returnType == null) { return null; } return reflectedTypeFactory.reflect(returnType); } @Override public String property() { final String name = name(); if (name.length() > 2) { if (name.length() > 3) { if (name.startsWith("get") || name.startsWith("set")) { return initialLowerCase(name.substring(3)); } } if (name.startsWith("is")) { return initialLowerCase(name.substring(2)); } } return method.getName(); } private String initialLowerCase(final String substring) { return substring.substring(0, 1).toLowerCase() + substring.substring(1); } @Override public Method member() { return method; } @Override public Visibility visibility() { return visibilityFromModifiers(method.getModifiers()); } private List<TypeVariable<Method>> typeParameters() { return Arrays.asList(method.getTypeParameters()); } @Override public String toString() { final String visibility; if (visibility().toString().isEmpty()) { visibility = visibility().toString(); } else { visibility = visibility().toString() + " "; } final String staticModifier; if (isStatic()) { staticModifier = "static "; } else { staticModifier = ""; } final String finalModifier; if (isFinal()) { finalModifier = "final "; } else { finalModifier = ""; } final String typeParameters; if (typeParameters().isEmpty()) { typeParameters = ""; } else { typeParameters = "<" + joinFrom(typeParameters(), ", ").toString() + "> "; } final String arguments; if (argCount() > 0) { arguments = joinFrom(args(), ", ").toString(); } else { arguments = ""; } return format("%s%s%s%s%s %s(%s)", visibility, staticModifier, finalModifier, typeParameters, type(), method.getName(), arguments); } @Override public boolean equals(final Object obj) { if (obj != null && this.getClass().equals(obj.getClass())) { final FluentMethodImpl that = (FluentMethodImpl) obj; return new EqualsBuilder().append(this.method, that.method).append(this.typeLiteral, that.typeLiteral) .isEquals(); } return false; } @Override public int hashCode() { return new HashCodeBuilder().append(method).append(typeLiteral).toHashCode(); } @Override public FluentMethod rebind(final Object receiver) { return object(receiver).method(compatibleWith(this)); } }