package com.github.czyzby.uedi.stereotype.impl; import java.lang.reflect.Member; import com.badlogic.gdx.utils.reflect.Method; import com.github.czyzby.uedi.Context; import com.github.czyzby.uedi.reflection.impl.MethodMember; import com.github.czyzby.uedi.stereotype.Default; import com.github.czyzby.uedi.stereotype.Named; /** Wraps around a method, converting it into a provider. * * @author MJ */ public class ReflectionProvider implements DelegateProvider<Object>, Named { private final Context context; private final Method method; private final Class<?> type; private final Object owner; private final Class<?>[] parameterTypes; private final Object[] parameters; private final String name; private final boolean isDefault; private final Member methodMember; /** @param context parent context. * @param owner instance of the class with the method. * @param method will be wrapped and converted into a provider. */ public ReflectionProvider(final Context context, final Object owner, final Method method) { this.context = context; this.owner = owner; this.method = method; type = method.getReturnType(); parameterTypes = method.getParameterTypes(); parameters = parameterTypes.length == 0 ? Providers.EMPTY_ARRAY : new Object[parameterTypes.length]; name = Providers.getName(method); isDefault = owner instanceof Default; methodMember = new MethodMember(method); } @Override public boolean isDefault() { return isDefault; } @Override public Object getWrappedObject() { return owner; } @Override public String getName() { return name; } @Override public Class<? extends Object> getType() { return type; } @Override public Object provide(final Object target, final Member member) { try { if (parameters.length == 0) { return method.invoke(owner, parameters); } final Class<?> targetType = target == null ? null : target.getClass(); for (int index = 0, length = parameters.length; index < length; index++) { final Class<?> parameterType = parameterTypes[index]; parameters[index] = parameterType == Object.class || parameterType == targetType ? target : context.get(parameterType, owner, methodMember); } return method.invoke(owner, parameters); } catch (final RuntimeException exception) { throw exception; } catch (final Exception exception) { throw new RuntimeException("Unable to invoke method: '" + method.getName() + "' of component: " + owner, exception); } } }