Java 替换的freemarker模板字段中不需要的引号
我从Freemarker模板生成内容,但我在替换字段中得到引用值 对于JSON对象Java 替换的freemarker模板字段中不需要的引号,java,json,javabeans,freemarker,Java,Json,Javabeans,Freemarker,我从Freemarker模板生成内容,但我在替换字段中得到引用值 对于JSON对象 { "name" : "Pepster" } 在模板中: Hi ${name}! 我明白了 当我想 Hi Pepster! 我为其提供的对象是一个JsonNode树,通过将我的对象映射到Jackson注释获得: class Name { @JsonProperty("name") public String mName; } 处理器: final ObjectMapper mapper
{
"name" : "Pepster"
}
在模板中:
Hi ${name}!
我明白了
当我想
Hi Pepster!
我为其提供的对象是一个JsonNode树,通过将我的对象映射到Jackson注释获得:
class Name {
@JsonProperty("name")
public String mName;
}
处理器:
final ObjectMapper mapper = new ObjectMapper();
JsonNode jsonDocument = mapper.valueToTree(nameObject);
//...
template.process(jsonDocument, writer);
我觉得我缺少了某种配置?FreeMarker没有添加引号,
JsonNode
的toString()
方法肯定会添加引号。您需要使用一个定制的(已初始化的)ObjectWrapper
,它知道应该调用getTextValue()
(或类似的东西)来提取字符串
值。JSON number也会有同样的问题,其中ObjectWrapper
应该调用getNumberValue()
。或者,如果您不想投资定制的ObjectWrapper
,${name.textValue}
当然可以工作,但是如果您有很多模板,这就有点尴尬了。下面是一个定制ObjectWrapper的示例实现,它可以正确处理
解决方案缺少对Jackson NullNode的处理。NullNode应该通过返回一个总是生成null的模型工厂来处理。哦,谢谢@Nathan,我也遇到了这个问题,但是忘记更新答案了
final ObjectMapper mapper = new ObjectMapper();
JsonNode jsonDocument = mapper.valueToTree(nameObject);
//...
template.process(jsonDocument, writer);
package com.sample.templates;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.*;
import freemarker.core.CollectionAndSequence;
import freemarker.ext.beans.BeanModel;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.IteratorModel;
import freemarker.ext.util.ModelFactory;
import freemarker.template.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
class JsonAwareObjectWrapper extends DefaultObjectWrapper {
public JsonAwareObjectWrapper(Version incompatibleImprovements) {
super(incompatibleImprovements);
}
private static class JsonNullNodeModel {
static final ModelFactory FACTORY = new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return null;
}
};
}
private static class JsonTextNodeModel extends BeanModel
implements TemplateScalarModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonTextNodeModel(object, (BeansWrapper) wrapper);
}
};
JsonTextNodeModel(Object object, BeansWrapper wrapper) {
super(object, wrapper);
}
/**
* Returns the result of calling {@link TextNode#asText()} on the wrapped
* TextNode.
*/
public String getAsString() {
return ((TextNode) object).asText();
}
}
private static class JsonNumberNodeModel extends
BeanModel
implements
TemplateNumberModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonNumberNodeModel(object, (BeansWrapper) wrapper);
}
};
JsonNumberNodeModel(Object object, BeansWrapper wrapper) {
super(object, wrapper);
}
@Override
public Number getAsNumber() throws TemplateModelException {
return ((NumericNode) object).numberValue();
}
}
private static class JsonBooleanNodeModel extends BeanModel implements TemplateBooleanModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonBooleanNodeModel(object, (BeansWrapper) wrapper);
}
};
JsonBooleanNodeModel(Object object, BeansWrapper wrapper) {
super(object, wrapper);
}
@Override
public boolean getAsBoolean() throws TemplateModelException {
return ((BooleanNode) object).asBoolean();
}
}
private static class JsonPOJONodeModel extends BeanModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonPOJONodeModel(((POJONode) object).getPojo(), (BeansWrapper) wrapper);
}
};
JsonPOJONodeModel(Object object, BeansWrapper wrapper) {
super(object, wrapper);
}
}
private static class JsonObjectNodeModel extends BeanModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonObjectNodeModel(object, (BeansWrapper) wrapper);
}
};
JsonObjectNodeModel(Object object, BeansWrapper wrapper) {
super(object, wrapper);
}
@Override
public TemplateModel get(String key) throws TemplateModelException {
ObjectNode objectNode = (ObjectNode) object;
final JsonNode jsonNode = objectNode.get(key);
if (jsonNode != null)
return wrap(jsonNode);
else
return null;
}
@Override
public boolean isEmpty() {
ObjectNode objectNode = (ObjectNode) object;
return objectNode.size() == 0;
}
@Override
public int size() {
ObjectNode objectNode = (ObjectNode) object;
return objectNode.size();
}
@Override
public TemplateCollectionModel keys() {
ObjectNode objectNode = (ObjectNode) object;
return new IteratorModel(objectNode.fieldNames(), wrapper);
}
@Override
public TemplateCollectionModel values() throws TemplateModelException {
ObjectNode objectNode = (ObjectNode) object;
List<JsonNode> values = new ArrayList<>(size());
final Iterator<Map.Entry<String, JsonNode>> it = objectNode.fields();
while (it.hasNext()) {
JsonNode value = it.next().getValue();
values.add(value);
}
return new CollectionAndSequence(new SimpleSequence(values, wrapper));
}
}
private static class JsonArrayNodeModel extends BeanModel
implements
TemplateCollectionModel,
TemplateSequenceModel {
static final ModelFactory FACTORY =
new ModelFactory() {
public TemplateModel create(Object object, ObjectWrapper wrapper) {
return new JsonArrayNodeModel(object, (BeansWrapper) wrapper);
}
};
private class Iterator
implements
TemplateSequenceModel,
TemplateModelIterator {
private int position = 0;
public boolean hasNext() {
return position < length;
}
public TemplateModel get(int index)
throws
TemplateModelException {
return JsonArrayNodeModel.this.get(index);
}
public TemplateModel next()
throws
TemplateModelException {
return position < length ? get(position++) : null;
}
public int size() {
return JsonArrayNodeModel.this.size();
}
}
private final int length;
JsonArrayNodeModel(Object array, BeansWrapper wrapper) {
super(array, wrapper);
ArrayNode arrayNode = (ArrayNode) array;
length = arrayNode.size();
}
@Override
public TemplateModelIterator iterator() {
return new Iterator();
}
@Override
public TemplateModel get(int index) throws TemplateModelException {
try {
return wrap(((ArrayNode) object).get(index));
} catch (IndexOutOfBoundsException e) {
return null;
}
}
@Override
public int size() {
return length;
}
@Override
public boolean isEmpty() {
return length == 0;
}
}
@Override
protected ModelFactory getModelFactory(Class clazz) {
if (TextNode.class.isAssignableFrom(clazz)) {
return JsonTextNodeModel.FACTORY;
} else if (NumericNode.class.isAssignableFrom(clazz)) {
return JsonNumberNodeModel.FACTORY;
} else if (BooleanNode.class.isAssignableFrom(clazz)) {
return JsonBooleanNodeModel.FACTORY;
} else if (POJONode.class.isAssignableFrom(clazz)) {
return JsonPOJONodeModel.FACTORY;
} else if (ArrayNode.class.isAssignableFrom(clazz)) {
return JsonArrayNodeModel.FACTORY;
} else if (ObjectNode.class.isAssignableFrom(clazz)) {
return JsonObjectNodeModel.FACTORY;
} else if (NullNode.class.isAssignableFrom(clazz)) {
return JsonNullNodeModel.FACTORY;
} else {
return super.getModelFactory(clazz);
}
}
}
final ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put("string", "jsonValue");
objectNode.put("int", 10);
objectNode.put("float", 3.14f);
objectNode.put("bool", true);
final ArrayNode arrayNode = objectMapper.createArrayNode();
arrayNode.add("arrayValue0");
arrayNode.add("arrayValue1");
objectNode.set("array", arrayNode);
final ObjectNode subObject = objectMapper.createObjectNode();
subObject.put("bool", false);
objectNode.set("subobject", subObject);
PojoSample pojoSample = new PojoSample();
pojoSample.setName("pojo");
pojoSample.setValue(100);
objectNode.set("pojo", new POJONode(pojoSample));
SimpleHash model = new SimpleHash(objectWrapper);
model.put("form", request.getForm());
model.put("env", request.getEnvironment());
model.put("json", objectNode);
stringLoader.putTemplate("simple",
"Json test: \n" +
"String ${json.string}\n" +
"Integer ${json.int}\n" +
"Float ${json.float}\n" +
"Boolean ${json.bool?c}\n" +
"Sub Object ${json.subobject.bool?c}\n" +
"Sub Array ${json.array[1]}\n" +
"Pojo: name = ${json.pojo.name}, value = ${json.pojo.value}");
Template temp = cfg.getTemplate("simple");
StringWriter out = new StringWriter();
temp.process(model, out);