代理对象属性

时间:2014-05-05 18:34:17

标签: freemarker

我想知道,是否有可能在freemarker模板模型中实现某种属性代理/范围继承? 考虑一下:

public class A {
    String aProperty;
}

public class B {
    String bProperty;
    A parent;
}

因此,在我的模板中,我可以编写类似${obj.aProperty}的内容,它可以检索 aProperty obj直接来自objAparent.aProperty的实例),如果没有,则obj B BeansWrapperpublic interface TemplateModelObject { String getaProperty(); } public class BProxy implements InvocationHandler { private B target; public BProxy(B target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass().equals(TemplateModelObject.class)) { return method.invoke(target.getParent(), args); } else { return method.invoke(target, args); } } } )的实例。

我唯一要做的就是使用自定义A implements TemplateModelObject,但也许还有其他侵入性较小的解决方案?任何帮助将不胜感激。

更新

Proxy的解决方案。

public  class CustomWrapper extends BeansWrapper {
    public TemplateModel wrap(Object object) throws TemplateModelException {
        if (object != null && B.class.isAssignableFrom(object.getClass())) {
            try {
                return super.wrap(Proxy.newProxyInstance(TemplateModelObject.class.getClassLoader(), new Class[]{TemplateModelObject.class}, new BProxy((B) object)));
            } catch (Exception e) {
                throw new TemplateModelException(e);
            }
        } else {
            return super.wrap(object);
        }
    }
}

假设B

CustomWrapper

我还需要一个声明{{1}}特定成员的接口,以便可以通过代理访问它们。但主要的问题是:不会{{1}}在Freemarker中破坏某些内容吗?

3 个答案:

答案 0 :(得分:1)

如果没有自定义ObjectWrapper,我认为你无法做到这一点。毕竟,这就是整个ObjectWrapper概念存在的原因。过去的问题是,几乎每个人都想要BeansWrapper的功能,从而以某种方式扩展它,并且经常证明这并不容易。就像这里一样,我的第一个猜测是你应该覆盖BeanModel.get(String),这样当它返回null时,它会接受父对象,用BeanModel.wrapper包裹它,然后委托给{{}包装对象的1}}但直接覆盖get(String)中的get无效,因为它只是BeansWrapper创建的TemplateModel类的超类。相反,您必须覆盖BeansWrapper的所有子类中的get,然后覆盖BeanModel中的getModelFactory(如果内存服务器良好...),以便{{1将创建BeansWrapper类的实例而不是标准类。

答案 1 :(得分:0)

您可以像

一样访问它

使用A的实例

${obj.aProperty}

以B的实例,

${obj.bProperty}

${obj.parent.aProperty} // if parent is null then you will get error

//所以首先检查父对象不为null,然后访问它的属性

<#if obj.parent?has_content >
${obj.parent.aProperty}
</#if>

答案 2 :(得分:0)

这适用于您的基本示例。该模板包含将对象传递给的函数以及属性的名称。它检查属性是否存在,如果不存在则从父级获取相同的属性。您需要对其进行扩展以进一步检查父项是否存在或者您是否需要多个级别。

A.java

package com.cluboramic.web.controllers;

public class A {

    private String property;

    public String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        this.property = property;
    }

}

B.java

package com.cluboramic.web.controllers;

public class B {

    private String property;

    private A parent;

    public String getProperty() {
        return property;
    }

    public void setProperty(String property) {
        this.property = property;
    }

    public A getParent() {
        return parent;
    }

    public void setParent(A parent) {
        this.parent = parent;
    }

}

对象设置

A a = new A();
a.setProperty("This is A");

B b1 = new B();
b1.setParent(a);

B b2 = new B();
b2.setProperty("This is B2");
b2.setParent(a);

模板

a = ${proxyProp(a "property")},

b1 = ${proxyProp(b1 "property")},

b2 = ${proxyProp(b2 "property")}

<#--
    obj is the object to access
    property is the name of the property
-->
<#function proxyProp obj property>
    <#if obj[property]??>
        <#return obj[property]>
    <#else>
        <#return obj.parent[property]>
    </#if>
</#function>

输出

a = This is A, b1 = This is A, b2 = This is B2