両方が同じかどうかにかかわらず、freemarker内の2つのJavaオブジェクトを比較する必要があります。freemarkerで2つのJavaオブジェクトの同等性をチェックする方法はありますか
1 に答える
残念ながら、2.3.19の時点では、すぐに使用できる可能性はありません。おそらく2.3.20かそこらにあるでしょう。TemplateMethodModelEx
これを実装するには、のようなを作成する必要がありますsameObjects(p1, p2)
。TemplateModel
その中で、パラメータ-sから生のオブジェクトを抽出する必要があります。そのためには、パラメータが実装されているかどうかを確認してから、をAdapterTemplateModel
呼び出す必要がありますAdapterTemplateModel.getAdaptedObject(Object.class)
。次に、生のオブジェクトを==
、まだJavaで、と比較して、 true
/を返すことができますfalse
。
更新:これをFreeMarkerに提供するつもりなので、さらに調査を行いました。使用AdapterTemplateModel
はこれに対して完全に正しいわけではありません。これは、変換(PythonからJavaなど)が含まれる可能性があり、元のオブジェクトのIDが失われ、フォールスネガティブが発生する可能性があるためです。を使用WrapperTemplateModel
すると解決策のように見えますが、Jythonの実装が間違っていることがわかります...したがって、間違った結果が得られない(ただし、比較が不可能なためにエラーが発生する可能性がある)唯一の解決策は、を使用することですBeanModel
。具体的な実装は次のとおりです。
package com.example;
import java.util.List;
import freemarker.ext.beans.BeanModel;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
/**
* Checks if two values correspond to the same object. This only works if both
* arguments are wrapped into {@link BeanModel}-s by the object wrapping
* facility of FreeMarker, which is usually the case for objects that aren't
* {@code Collection}-s, {@code Map}-s, {@code String}-s, {@code Number}-s,
* {@code Date-s}, {@code Boolean}-s, Jython objects, Rhino objects or DOM
* objects. If you are using pure {@link BeansWrapper} for wrapping, this is the
* case for all objects. If not all the arguments are {@link BeanModel}-s, or
* some of them are {@code null}-s, this will throw an exception.
*/
public class IsSameObjectMethodModel implements TemplateMethodModelEx {
public Object exec(List args) throws TemplateModelException {
if (args.size() != 2) {
throw new TemplateModelException(
"Method expects exactly 2 arguments, but " +
args.size() + " was given.");
}
return toRawArg("1st", args.get(0)) == toRawArg("2nd", args.get(1)) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
/**
* Extracts the original object from the argument.
* @param argName Used in error messages
*/
private Object toRawArg(String argName, Object argVal)
throws TemplateModelException {
if (argVal == null) throw new TemplateModelException(
"Method doesn't support null arguments, but the " +
argName + " argument was null");
if (argVal instanceof BeanModel) {
return ((BeanModel) argVal).getWrappedObject();
} else {
throw new TemplateModelException(
"Method only supports arguments that were wrapped by " +
"FreeMarker (or something else) so that they extend " +
"freemarker.ext.beans.BeanModel, but " +
"the " + argName + " argument wasn't like that (class: " +
argVal.getClass().getName() + "). To avoid this error, " +
"avoid comparing objects that are Collection-s, " +
"Map-s, String-s, Number-s, Date-s, Boolean-s, Jython " +
"objects, Rhino objects or DOM objects.");
}
}
}
これを使用するには、データモデルに配置するか、インポート/インクルードに使用したテンプレートがあると仮定して、次のようにしますutils.ftl
。
...
[#assign isSameObject = "com.example.IsSameObjectMethodModel"?new()]
...
次に、テンプレートで:
[#import "utils.ftl" as u]
...
[#if u.isSameObject(o1, o2)]
same
[#else]
different
[/#if]