Checking if class is proxified with CDI 1.2
Asked Answered
O

3

6

In CDI 1.2 there is a way to check if a class instance is proxified? I need this because I need to get the name of original class, not the proxy name.

@Inject Bean bean;

public void sysout() {
    // will print something like com.Bean$$Weld9239823
    System.out.println(bean.getClass()); 

    // I don't know how to check if the bean instance if a proxy or real class instance
}

Using Weld classes I can do this job:

public void sysout() {
    // will print true because this is a proxy
    System.out.println(ProxyObject.class.isAssignableFrom(bean)); 

    // will print com.Bean
    System.out.println(((TargetInstanceProxy) bean).getTargetInstance());
}

In CDI 1.1 there is no method to do this. I search inside CDI 1.2 docs if a method was added about this, but I don't found anything.

So... I miss something and CDI 1.2 there is a method to get original class name and instance? Or if not, there is a plain to add this feature in near feature?

Omidyar answered 29/8, 2014 at 17:40 Comment(2)
What is the use case for finding out the class of the bean? Considering that you're injecting Bean bean you already know that it implements BeanTelium
Have you tried this solution? https://mcmap.net/q/702315/-java-detect-if-class-is-a-proxyDeciare
E
2

For Weld on WildFly do this:

public boolean isProxy(Object obj) {
    try{
        return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
    } catch (Exception e) {
        log.error("Unable to check if object is proxy", e);
    }
    return false;
}

To retrive actual object instead of proxy (I need to serialize it) I do this:

public Object getObject(Object obj) {
    Field f = null;
    boolean isAccessible = false;
    try {
        for(Field fi : Class.forName(handler).getDeclaredFields()) {
            if(fi.getName().equals(field)) {
                f = fi;
                isAccessible = f.isAccessible();
                f.setAccessible(true);
            }
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    if(f == null) {
        throw new RuntimeException(new NoSuchFieldException(String.format(
                "The required field '%s' not found in '%s'. " +
                        "May be the code is obsolete for running on this application server.",
                field, method)));
    } else {
        try{
            obj = f.get(getHandler(obj));
            for(Method m : Class.forName(instance).getMethods()) {
                if(m.getName().equals(value)) {
                    return m.invoke(obj);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            f.setAccessible(isAccessible);
        }
        throw new NoSuchMethodError(String.format(
               "The required method '%s' not found in '%s'. " +
                       "May be the code is obsolete for running on this application server.",
                value, instance));
    }
}

Be aware, that it is the darkest magic as possible, have very poor performance and can break at any WildFly update, if they change classes, methods for fields in it.

Evangelical answered 5/6, 2015 at 15:19 Comment(0)
J
0

This is a terrible hack, but for Weld (and possibly other implementations) you can check if the class name contains "Proxy": possibleProxy.getClass().getSimpleName().contains("Proxy"). I use it only for logging purposes to get a cleaned up version of the wrapped class name:

/**
 * Get the actual simple name of the objects class that might be wrapped by
 * a proxy. A "simple" class name is not fully qualified (no package name).
 *
 * @param possibleProxy an object that might be a proxy to the actual
 * object.
 * @return the simple name of the actual object's class
 */
public static String getActualSimpleClassName(final Object possibleProxy) {
    final String outerClassName = possibleProxy.getClass().getSimpleName();
    final String innerClassName;
    if (outerClassName.contains("Proxy")) {
        innerClassName = outerClassName.substring(0, outerClassName.indexOf('$'));
    } else {
        innerClassName = outerClassName;
    }
    return innerClassName;
}
Jot answered 5/1, 2015 at 23:8 Comment(0)
M
0

you can make a method inside your proxied cdi bean like

public String getClassName() {
    return this.getClass().getName();
}

this is not the best solution, but a simple pragmatic way to get the class name through the proxy... the downside of this is that the method must be on every implementation...

Marquand answered 22/1, 2015 at 19:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.