Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 防止调用实例的实例方法_Java_Reflection - Fatal编程技术网

Java 防止调用实例的实例方法

Java 防止调用实例的实例方法,java,reflection,Java,Reflection,我认识到这可能是一个问题,所以我将解释上下文,以防有比我尝试做的更好的解决方案 我试图添加从JSP中的EL表达式中访问类的静态方法的功能 到目前为止,我的解决方案是实例化指定的类并将其放在页面(或指定的)范围内。因为您可以从实例访问静态方法,所以它似乎是最简单、最直接的解决方案。为此,我编写了一个标记类,StaticMethodAccessTag,并将其作为常量:staticMethodAccess添加到一个tld中 这个解决方案的问题是,也可以调用非静态方法,这意味着可能出现问题和滥用 有没有

我认识到这可能是一个问题,所以我将解释上下文,以防有比我尝试做的更好的解决方案

我试图添加从JSP中的EL表达式中访问类的静态方法的功能

到目前为止,我的解决方案是实例化指定的类并将其放在页面(或指定的)范围内。因为您可以从实例访问静态方法,所以它似乎是最简单、最直接的解决方案。为此,我编写了一个标记类,
StaticMethodAccessTag
,并将其作为
常量:staticMethodAccess
添加到一个tld中

这个解决方案的问题是,也可以调用非静态方法,这意味着可能出现问题和滥用

有没有一种方法可以使用反射来实例化一个类的实例,同时防止(例如通过抛出异常)调用任何非静态方法

或者更好的是,有没有一种方法可以通过EL“调用”任何任意命名和参数化的方法,并让一个java方法处理所有这些调用?类似于
${MyStaticUtil.foo(bar1,bar2)}
${MyStaticUtil.baz(bar1)}
这两种方法都将进入
StaticMethodAccessTag.ProcessArbiaryMethod(String methodName,Object…args)
,然后可以使用反射来调用
MyStaticUtil
上适当的静态方法

或者更好的是,有没有一种方法可以在EL中调用静态方法,而不需要类的实例来调用它


StaticMethodAccessTag.java:

import java.lang.reflect.Constructor;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import org.apache.log4j.Logger;

public class StaticMethodAccessTag extends SimpleTagSupport {

    private static Logger log = Logger.getLogger(StaticMethodAccessTag.class);

    private String varName;
    private String className;
    private String scope;
    private Object[] args;

    @Override
    public void doTag() throws JspException {
        try {
            if (scope == null || "".equals(scope)) {
                scope = "page";
            }
            int requestedScope = TagUtils.getScope(scope);

            Class<?> declaringClass = Class.forName(this.className);
            Object instance = null;
            Class<?>[] argTypes = null;

            if (args == null || args.length == 0) {
                // no args; use default constructor
                instance = declaringClass.newInstance();
            } else {
                // args provided, find the matching constructor and use it
                argTypes = new Class<?>[args.length];
                for (int i = 0; i < args.length; i++) {
                    if (args[i] == null) {
                        // unknown type, assume Object. This can lead to ambiguity when picking a constructor.
                        argTypes[i] = Object.class;
                    } else {
                        argTypes[i] = args[i].getClass();
                    }
                }

                // check each constructor
                Constructor<?> matchedConstructor = null;
                nextConstructor: for (Constructor<?> constructor : declaringClass.getConstructors()) {
                    Class<?>[] expectedTypes = constructor.getParameterTypes();

                    // check the provided arguments against the current constructor
                    if (expectedTypes == null || expectedTypes.length != args.length) {
                        // mismatch; move on to the next constructor
                        continue;
                    }
                    for (int i = 0; i < argTypes.length; i++) {
                        if (!argTypes[i].isAssignableFrom(expectedTypes[i])) {
                            // mismatch; move on to the next constructor
                            continue nextConstructor;
                        }
                    }

                    // if another match was already found, that means we have ambiguous arguments.
                    if (matchedConstructor != null) {
                        outputArgs(argTypes);
                        throw new Exception("Given the provided arguments, there are multiple eligible constructors for " + declaringClass.getName());
                    }

                    matchedConstructor = constructor;
                }

                if (matchedConstructor != null) {
                    instance = matchedConstructor.newInstance(args);
                }
            }

            if (instance == null) {
                outputArgs(argTypes);
                throw new NullPointerException("Failed to find a matching constructor for the provided args for " + this.className + ".");
            }

            getJspContext().setAttribute(varName, instance, requestedScope);
        } catch (Exception e) {
            // TODO output jsp name, other helpful information, if possible.
            throw new JspException("Exception setting up static method access for " + this.className, e);
        }
    }

    private void outputArgs(Class<?>[] argTypes) {
        log.debug("Provided " + args.length + " arguments: ");
        for (int i = 0; i < argTypes.length; i++) {
            String argStr = "null";
            if (args[i] != null) {
                argStr = args[i].toString();
            }
            log.debug("[" + i + "] expected type: " + argTypes[i].getName() + " toString: " + argStr);
        }
    }

    public String getVar() {
        return varName;
    }

    public void setVar(String varName) {
        this.varName = varName;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public Object[] getArgs() {
        return args;
    }

    public void setArgs(Object... args) {
        this.args = args;
    }
}
import java.lang.reflect.Constructor;
导入javax.servlet.jsp.JspException;
导入javax.servlet.jsp.tagext.SimpleTagSupport;
导入org.apache.log4j.Logger;
公共类StaticMethodAccessTag扩展了SimpleTagSupport{
私有静态记录器log=Logger.getLogger(StaticMethodAccessTag.class);
私有字符串varName;
私有字符串类名;
私有字符串范围;
私有对象[]args;
@凌驾
public void doTag()抛出JSPEException{
试一试{
如果(范围==null | |“”.equals(范围)){
scope=“page”;
}
int requestedScope=TagUtils.getScope(范围);
Class declaringClass=Class.forName(this.className);
对象实例=null;
类[]argTypes=null;
if(args==null | | args.length==0){
//无参数;使用默认构造函数
instance=declaringClass.newInstance();
}否则{
//如果提供了args,请找到匹配的构造函数并使用它
argTypes=新类[args.length];
对于(int i=0;i<tag>
    <name>staticMethodAccess</name>
    <tagclass>foopackage.presentation.resource.tag.StaticMethodAccessTag</tagclass>
    <bodycontent>empty</bodycontent>
    <attribute>
        <name>className</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>var</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <name>scope</name>
        <required>false</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>args</name>
        <required>false</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
<%@ taglib prefix="constants" uri="/constants" %>

<%-- debug, delete this block --%>
<constants:staticMethodAccess var="MyJSPUtils" className="foopackage.presentation.resource.tag.MyJSPUtils"/>
<c:forEach items="${MyJSPUtils.args('one', 'two', 'three')}" var="v">
    ${v};
</c:forEach>
<constants:staticMethodAccess var="type1" className="foopackage.integration.value.Type" args="${jspUtils.args(DBConstants.STATUS_TYPE_ID_ACTIVE)}"/>
<constants:staticMethodAccess var="type2" className="foopackage.integration.value.Type" args="${jspUtils.args(DBConstants.STATUS_TYPE_ID_ACTIVE, 'Active')}"/>
<constants:staticMethodAccess var="type3" className="foopackage.integration.value.Type" args="${jspUtils.args(type1)}"/>
<constants:staticMethodAccess var="type4" className="foopackage.integration.value.Type" args="${jspUtils.args(DBConstants.STATUS_TYPE_ID_ACTIVE, 'Active', 'desc')}"/>
<constants:staticMethodAccess var="type5" className="foopackage.integration.value.Type" args="${jspUtils.args(DBConstants.STATUS_TYPE_ID_ACTIVE, null, 'desc')}"/>
<constants:staticMethodAccess var="type3" className="foopackage.integration.value.Type" args="${jspUtils.args(null)}"/><%-- this line will throw an error because it matches 2 possible constructors --%>

<br/>${type1.id} ${type1.name} ${type1.description}
<br/>${type2.id} ${type2.name} ${type2.description}
<br/>${type3.id} ${type3.name} ${type3.description}
<br/>${type4.id} ${type4.name} ${type4.description}
<br/>${type5.id} ${type5.name} ${type5.description}
<br/>
<%-- end debug block --%>
public Object callOnlyStaticMethods(String name, Class [] parameterTypes, Object [] parameters) throws Exception {

    // use getDeclaredMethod and setAccessible if you want to call non-public methods
    Method method =  this.getClass().getMethod(name, parameterTypes);
    if( ! Modifier.isStatic(method.getModifiers()) ) {
        throw new UnsupportedOperationException("Only static methods may be called, " + method.getName() + " is not static!");
    }
    return method.invoke(null, parameters);
}
public class MyStaticUtil implements InvocationHandler {

    /* (non-Javadoc)
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // it's just a lot easier if all method names in StaticMethodAccessTag are unique..
        String methodName = method.getName();

        Method methodToCall = null;
        for( Method realMethod : StaticMethodAccessTagInterface.class.getMethods() ) {
           if( realMethod.getName().equals(methodName) )  {
               methodToCall = realMethod;
               break;
           }
        }
        // check if the method has actually been found or not, otherwise possible NPE's..

        return methodToCall.invoke(null, args);
    }

    private final static MyStaticUtil _instance = new MyStaticUtil();

    public static Object getInstance() {
        Class [] proxyInterfaces = {
          StaticMethodAccessTagInterface.class
        };
        return Proxy.newProxyInstance(
                MyStaticUtil.class.getClassLoader(),
                proxyInterfaces,
                _instance);

    }

}