All Downloads are FREE. Search and download functionalities are using the official Maven repository.

autofixture.generators.objects.implementationdetails.InterfaceHandler Maven / Gradle / Ivy

package autofixture.generators.objects.implementationdetails;

import autofixture.interfaces.FixtureContract;
import autofixture.interfaces.InstanceType;
import com.google.common.base.Optional;
import com.google.common.reflect.TypeToken;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class InterfaceHandler implements InvocationHandler {

  private final FixtureContract fixture;
  private final InstanceType instanceType;
  private final MethodsInvocationResultCache methodsInvocationResultCache = new MethodsInvocationResultCache();

  public InterfaceHandler(final FixtureContract fixture, final InstanceType instanceType) {
    this.fixture = fixture;
    this.instanceType = instanceType;
  }

  @Override
  public Object invoke(final Object proxy, final Method method, final Object[] arguments) throws Exception {

    final TypeToken returnType = instanceType.resolveActualTypeOf(method);

    if (isHashCodeMethod(method)) {
      return System.identityHashCode(proxy);
    }

    if (isEqualsMethod(method, arguments)) {
      return proxy == arguments[0];
    }

    if (wasCalledAtLeastOnceOn(proxy, method)) {
      return methodsInvocationResultCache.getResultFor(proxy, method);
    }

    return generateFreshValueFor(proxy, method, returnType);
  }

  private boolean isHashCodeMethod(final Method method) {
    return "hashCode".equals(method.getName());
  }

  private boolean wasCalledAtLeastOnceOn(final Object proxy, final Method method) {
    return methodsInvocationResultCache.containAResultFor(proxy, method);
  }

  private boolean isEqualsMethod(final Method mtd, final Object[] arguments) {
    return "equals".equals(mtd.getName()) && arguments.length == 1;
  }

  //TODO check case when new X().GetValue() and new X().GetValue() afterwards - does this work?
  private Object generateFreshValueFor(final Object proxy, final Method method, final TypeToken returnType) {
    final Optional freshReturnValue = createReturnValue(fixture, returnType);
    if (freshReturnValue.isPresent()) {
      methodsInvocationResultCache.setFor(proxy, method, freshReturnValue.get());
    }
    return freshReturnValue.orNull();
  }

  private Optional createReturnValue(final FixtureContract fixture, final TypeToken returnType) {
    if (returnType.getRawType() != void.class) {
      final Object o = fixture.create(returnType);
      return Optional.of(o);
    } else {
      return Optional.absent();
    }
  }

}