Coverage Report - com.lexicalscope.fluentreflection.FluentMethodImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
FluentMethodImpl
77%
70/90
72%
26/36
2.571
FluentMethodImpl$1
0%
0/3
N/A
2.571
 
 1  0
 package com.lexicalscope.fluentreflection;
 2  
 
 3  
 /*
 4  
  * Copyright 2011 Tim Wood
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  * http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import static ch.lambdaj.Lambda.*;
 20  
 import static com.lexicalscope.fluentreflection.Visibility.visibilityFromModifiers;
 21  
 import static java.lang.String.format;
 22  
 import static java.lang.System.arraycopy;
 23  
 
 24  
 import java.lang.reflect.InvocationTargetException;
 25  
 import java.lang.reflect.Method;
 26  
 import java.lang.reflect.Modifier;
 27  
 import java.lang.reflect.TypeVariable;
 28  
 import java.util.ArrayList;
 29  
 import java.util.Arrays;
 30  
 import java.util.List;
 31  
 
 32  
 import org.apache.commons.lang3.builder.EqualsBuilder;
 33  
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 34  
 
 35  
 import com.google.inject.TypeLiteral;
 36  
 
 37  
 final class FluentMethodImpl extends AbstractFluentAnnotated implements FluentMethod {
 38  
     private final ReflectedTypeFactory reflectedTypeFactory;
 39  
     private final FluentClass<?> reflectedClass;
 40  
     private final TypeLiteral<?> typeLiteral;
 41  
     private final Method method;
 42  
 
 43  
     public FluentMethodImpl(
 44  
             final ReflectedTypeFactory reflectedTypeFactory,
 45  
             final FluentClass<?> reflectedClass,
 46  
             final TypeLiteral<?> typeLiteral,
 47  
             final Method method) {
 48  7772
         super(reflectedTypeFactory, method);
 49  7772
         this.reflectedTypeFactory = reflectedTypeFactory;
 50  7772
         this.reflectedClass = reflectedClass;
 51  7772
         this.typeLiteral = typeLiteral;
 52  7772
         this.method = method;
 53  7772
     }
 54  
 
 55  
     @Override public String name() {
 56  7422
         return method.getName();
 57  
     }
 58  
 
 59  
     @Override public List<FluentClass<?>> args() {
 60  802
         final List<FluentClass<?>> result = new ArrayList<FluentClass<?>>();
 61  1604
         result.addAll(convert(
 62  802
                 typeLiteral.getParameterTypes(method),
 63  802
                 new ConvertTypeLiteralToReflectedType(reflectedTypeFactory)));
 64  802
         return result;
 65  
     }
 66  
 
 67  
     @Override public int argCount() {
 68  1756
         final int parameterCount = method.getParameterTypes().length;
 69  1756
         if (isStatic()) {
 70  24
             return parameterCount;
 71  
         }
 72  1732
         return parameterCount;
 73  
     }
 74  
 
 75  
     @Override public FluentClass<?> declarer() {
 76  104
         return reflectedTypeFactory.reflect(typeLiteral);
 77  
     }
 78  
 
 79  
     @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public FluentObject<?> call(final Object... args) {
 80  0
         final Object object = callRaw(args);
 81  0
         if(object == null) {
 82  0
             return null;
 83  
         }
 84  0
         return reflectedTypeFactory.reflect((Class) object.getClass(), object);
 85  
     }
 86  
 
 87  
     @Override public Object callRaw(final Object... args) {
 88  540
         if (isStatic()) {
 89  32
             return invokeMethod(null, args);
 90  
         } else {
 91  508
             if (args.length < 1) {
 92  16
                 throw new IllegalArgumentException("target instance must be specified as first argument when calling "
 93  8
                         + method);
 94  
             }
 95  
 
 96  500
             final Object[] remainingArguments = new Object[args.length - 1];
 97  500
             arraycopy(args, 1, remainingArguments, 0, args.length - 1);
 98  500
             return invokeMethod(args[0], remainingArguments);
 99  
         }
 100  
     }
 101  
 
 102  
     private Object invokeMethod(final Object instance, final Object[] arguments) {
 103  
         try {
 104  532
             if (!method.isAccessible()) {
 105  476
                 method.setAccessible(true);
 106  
             }
 107  532
             return method.invoke(instance, arguments);
 108  8
         } catch (final IllegalArgumentException e) {
 109  8
             throw new IllegalArgumentRuntimeException(e, method, instance, arguments);
 110  0
         } catch (final IllegalAccessException e) {
 111  0
             throw new IllegalAccessRuntimeException(e, method);
 112  0
         } catch (final InvocationTargetException e) {
 113  0
             throw new InvocationTargetRuntimeException(e, method);
 114  
         }
 115  
     }
 116  
 
 117  
     @Override public boolean isStatic() {
 118  13560
         return Modifier.isStatic(method.getModifiers());
 119  
     }
 120  
 
 121  
     @Override public boolean isFinal() {
 122  144
         return Modifier.isFinal(method.getModifiers());
 123  
     }
 124  
 
 125  
     @Override public <T> FluentCall<T> as(final Class<T> returnType) {
 126  0
         return new AbstractCall<T>(reflectedTypeFactory) {
 127  
             @Override public T callRaw(final Object... args) {
 128  0
                 return returnType.cast(FluentMethodImpl.this.callRaw(args));
 129  
             }
 130  
         };
 131  
     }
 132  
 
 133  
     @Override public FluentClass<?> type() {
 134  1608
         final TypeLiteral<?> returnType = typeLiteral.getReturnType(method);
 135  1608
         if (returnType == null) {
 136  0
             return null;
 137  
         }
 138  1608
         return reflectedTypeFactory.reflect(returnType);
 139  
     }
 140  
 
 141  
     @Override public String property() {
 142  1408
         final String name = name();
 143  
 
 144  1408
         if (name.length() > 2) {
 145  1408
             if (name.length() > 3) {
 146  1408
                 if (name.startsWith("get") || name.startsWith("set")) {
 147  1376
                     return initialLowerCase(name.substring(3));
 148  
                 }
 149  
             }
 150  32
             if (name.startsWith("is")) {
 151  0
                 return initialLowerCase(name.substring(2));
 152  
             }
 153  
         }
 154  32
         return method.getName();
 155  
     }
 156  
 
 157  
     private String initialLowerCase(final String substring) {
 158  1376
         return substring.substring(0, 1).toLowerCase() + substring.substring(1);
 159  
     }
 160  
 
 161  
     @Override public Method member() {
 162  8
         return method;
 163  
     }
 164  
 
 165  
     @Override public Visibility visibility() {
 166  320
         return visibilityFromModifiers(method.getModifiers());
 167  
     }
 168  
 
 169  
     private List<TypeVariable<Method>> typeParameters()
 170  
     {
 171  160
         return Arrays.asList(method.getTypeParameters());
 172  
     }
 173  
 
 174  
     @Override public String toString() {
 175  
         final String visibility;
 176  144
         if (visibility().toString().isEmpty())
 177  
         {
 178  120
             visibility = visibility().toString();
 179  
         }
 180  
         else
 181  
         {
 182  24
             visibility = visibility().toString() + " ";
 183  
         }
 184  
 
 185  
         final String staticModifier;
 186  144
         if (isStatic())
 187  
         {
 188  16
             staticModifier = "static ";
 189  
         }
 190  
         else
 191  
         {
 192  128
             staticModifier = "";
 193  
         }
 194  
 
 195  
         final String finalModifier;
 196  144
         if (isFinal())
 197  
         {
 198  8
             finalModifier = "final ";
 199  
         }
 200  
         else
 201  
         {
 202  136
             finalModifier = "";
 203  
         }
 204  
 
 205  
         final String typeParameters;
 206  144
         if (typeParameters().isEmpty())
 207  
         {
 208  128
             typeParameters = "";
 209  
         }
 210  
         else
 211  
         {
 212  16
             typeParameters = "<" + joinFrom(typeParameters(), ", ").toString() + "> ";
 213  
         }
 214  
 
 215  
         final String arguments;
 216  144
         if (argCount() > 0) {
 217  48
             arguments = joinFrom(args(), ", ").toString();
 218  
         } else {
 219  96
             arguments = "";
 220  
         }
 221  
 
 222  144
         return format(
 223  144
                 "%s%s%s%s%s %s(%s)",
 224  144
                 visibility,
 225  144
                 staticModifier,
 226  144
                 finalModifier,
 227  144
                 typeParameters,
 228  144
                 type(),
 229  144
                 method.getName(),
 230  144
                 arguments);
 231  
     }
 232  
 
 233  
     @Override public boolean equals(final Object obj) {
 234  0
         if (obj != null && this.getClass().equals(obj.getClass())) {
 235  0
             final FluentMethodImpl that = (FluentMethodImpl) obj;
 236  0
             return new EqualsBuilder()
 237  0
                     .append(this.method, that.method)
 238  0
                     .append(this.typeLiteral, that.typeLiteral)
 239  0
                     .isEquals();
 240  
         }
 241  0
         return false;
 242  
     }
 243  
 
 244  
     @Override public int hashCode() {
 245  0
         return new HashCodeBuilder().append(method).append(typeLiteral).toHashCode();
 246  
     }
 247  
 }