我想知道,是否有可能在freemarker模板模型中实现某种属性代理/范围继承? 考虑一下:
public class A {
String aProperty;
}
public class B {
String bProperty;
A parent;
}
因此,在我的模板中,我可以编写类似${obj.aProperty}
的内容,它可以检索
aProperty
obj
直接来自obj
(A
是parent.aProperty
的实例),如果没有,则obj
B
BeansWrapper
是public 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中破坏某些内容吗?
答案 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