0

My goal is to create an instance for a class while invoking its getter method, after that set a value for the new instance fields. (in this case, shown at the code the class is a String, but it could be another class "Like Person class")

...Entity annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Entity {

    String visibileName();

}

...implementsIEventDesignDialog

      public class EventDesignDialog implements IEventDesignDialog{

        private String show;
        private String dateAndTimeDisplayFormat;
        private String eventType;


        @Entity(visibileName = "Show")
        public String getShow() {
            return this.show;
        }

        @Entity(visibileName = "Date And Time display format")
        public String getDateAndTimeDisplayFormat() {
            return this.dateAndTimeDisplayFormat;
        }

        @Entity(visibileName = "Event Type")
        public String getEventType() {
            System.out.println("get event type method invokde successfully");
            return this.eventType;
        }
}

IEventDesignDialog interface:

public interface IEventDesignDialog extends IPage{

    public String getShow();

    public String getDateAndTimeDisplayFormat();

    public String getEventType();


}

IPage interface:

public interface IPage {

}

Dynamic proxy implementation:

public class IPageProxy implements InvocationHandler {
    private List<Method> entityMethods;



    private Class <? extends IPage> screenClazz;

    public IPageProxy(final Class <? extends IPage> screenClazz) {
        entityMethods = new ArrayList<>();
        getEntityAnnotatedMethods(screenClazz);
        // Accept the real implementation to be proxied
        this.screenClazz = screenClazz;
    }


    /**
     * create an page instance
     * @param type
     * @param
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static IPage getInstance(final Class<? extends IPage> type)
            throws InstantiationException, IllegalAccessException {

        List<Class<?>> interfaces = new ArrayList<>();
        interfaces.addAll(Arrays.asList(type.getInterfaces()));

        return (IPage) Proxy.newProxyInstance(
                type.getClassLoader(),
                findInterfaces(type),
                new IPageProxy(type)
             );

        /*return (IPage) Proxy.newProxyInstance(type.getClassLoader(),
               interfaces.toArray(new Class<?>[interfaces.size()])
                , new IPageProxy(type));*/
    }


    /**
     * get all methods that annotated with @Entity annotation
     * and add it for entityMethods array List
     * @param screenClazz
     */
    private void getEntityAnnotatedMethods(final Class <? extends IPage>  screenClazz) {
        // Scan each interface method for the specific annotation
        // and save each compatible method
        for (final Method m : screenClazz.getDeclaredMethods()) {
            if (m.isAnnotationPresent(Entity.class)) {
                entityMethods.add(m);
            }
        }
    }


    static Class<?>[] findInterfaces(final Class<? extends IPage> type) {
        Class<?> current = type;

        do {
            final Class<?>[] interfaces = current.getInterfaces();

            if (interfaces.length != 0) {
                return interfaces;
            }
        } while ((current = current.getSuperclass()) != Object.class);

        throw new UnsupportedOperationException("The type does not implement any interface");
    }



  @Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws InvocationTargetException,
        IllegalAccessException, IllegalArgumentException, InstantiationException, ParserConfigurationException, XPathExpressionException, NoSuchFieldException, SecurityException {

    Method methodToInvoke = null;

    for (Method methodFromClass : screenClazz.getMethods()) {
        if (methodFromClass.getName().equals(method.getName())) {
            methodToInvoke = methodFromClass;
            break;
        }
    }



    String fieldName = method.getName().replaceAll("get", "");
    fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1, fieldName.length());

    Field getterMethodField = methodToInvoke.getDeclaringClass().getDeclaredField(fieldName);
    getterMethodField.setAccessible(true);

    Class<?> returnedType = method.getReturnType();

    try {
        *getterMethodField.set(getterMethodField.getType().newInstance(), "");*
    }catch (Exception e) {
        e.printStackTrace();
    }


    return methodToInvoke.invoke(screenClazz.newInstance(), args);
}

Main class:

public class Main {

    public static void main(String[] args) {
        try {

            ((EventDesignDialog)getInstance(EventDesignDialog.class)).getEventType();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    @SuppressWarnings("unchecked")
    public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
        return (T) IPageProxy.getInstance(type);
    }

}

The following exception is thrown when this line of code at invoke method: getterMethodField.set(getterMethodField.getType().newInstance(), "");

 java.lang.IllegalArgumentException: Can not set java.lang.String field abc.EventDesignDialog.eventType to java.lang.String
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:764)
at abc.IPageProxy.invoke(IPageProxy.java:173)
at com.sun.proxy.$Proxy2.getEventType(Unknown Source)
at abc.Main.main(Main.java:9)
1
  • Let me know if I wasn't clear enough. Sometimes I go too much into details. Commented Apr 4, 2019 at 10:41

1 Answer 1

1
methodToInvoke.getDeclaringClass()

returns Class<? extends IPage>.
While

getterMethodField.getType()

returns String.

Thus, you're trying to set the eventType field's value inside the java.lang.String class.
Not quite right ;)

 getterMethodField.set(getterMethodField.getType().newInstance(), "")
 ^---------------^     ^---------------------------------------^
      field of              new instance of java.lang.String
Class<? extends IPage>  Here you need an instance of ? extends IPage

What you need is

getterMethodField.getDeclaringClass().newInstance()

Anyway, I don't know what's the point of that, as the newly created instance get "lost" immediatly.
Maybe you wanted to do this?

    try {
        final Object instance = getterMethodField.getDeclaringClass().newInstance();
        getterMethodField.set(instance, "");
    } catch (final Exception e) {
        e.printStackTrace();
    }

    return methodToInvoke.invoke(instance, args);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.