gpt4 book ai didi

java - 避免简单框架输出中的空元素标记

转载 作者:行者123 更新时间:2023-12-01 04:51:04 26 4
gpt4 key购买 nike

避免"empty element tags"的正确方法是什么序列化所需元素时?

例子:

@ElementList(name="rpc", required=true)
public ArrayList<FunctionRequest> getRequestedFunctions() {
return requestedFunctions;
}

一个空列表将产生一个引用的“空元素标记”样式中的单个 XML 元素:

<rpc/>

我真正需要的是以下表示:

<rpc></rpc>

编辑:我需要不同类型列表的解决方案!例如,可能还有 List<String> , List<int> , List<WhateverClass> , ... 加上示例中为“rpc”的注释的不同名称属性。

谢谢你的帮助。

解决方案

我将首先介绍我实际实现的解决方案以及我在项目中使用的解决方案。之后,我将提出一个可以直接添加到简单代码中的更改建议。

我实际使用的解决方案:

由于我不想手动定义 XML 元素并为程序中的每个 List 创建一个转换器,因此我决定使用我的类的现有注释以及注释的名称属性。如果他们使用 getter 和 setter,我的解决方案将适用于将被序列化的类!它当前绑定(bind)到使用 Attribute 的类。和 Text注释,只有!

为了更灵活,我创建了一个“基础”类 RequestListConverter .它有两个 protected方法 prepareMethodListwriteRequest . prepareMethodList将使用反射遍历给定类的所有方法并创建一个方法注释映射。 writeRequest然后将写入给方法 prepareMethodList 的类型的单个对象到 write 中给出的 Simple 的 OutputNode Converter 的方法界面。

public class RequestListConverter {
private HashMap<Method, Object> curMethodAnnotationMap = new HashMap<Method, Object>();

@SuppressWarnings("rawtypes")
protected void prepareMethodList(Class targetClass) {
/*
* First, get the annotation information from the given class.
*
* Since we use getters and setters, look for the "get" methods!
*/

Method[] curMethods = targetClass.getMethods();
for (Method curMethod : curMethods) {
String curName = curMethod.getName();

// We only want getter methods that return a String
if (curName.startsWith("get") && (curMethod.getReturnType() == String.class)) {
Attribute curAttrAnnotation = curMethod.getAnnotation(Attribute.class);
Text curTextAnnotation = curMethod.getAnnotation(Text.class);

if (curAttrAnnotation != null) {
curMethodAnnotationMap.put(curMethod, curAttrAnnotation);
} else
if (curTextAnnotation != null) {
curMethodAnnotationMap.put(curMethod, curTextAnnotation);
}
}
}
}

protected void writeRequest(OutputNode curNode, Object curRequest) throws Exception {
for (Map.Entry<Method, Object> curMapEntry : curMethodAnnotationMap
.entrySet()) {
if ((curMapEntry.getKey() == null)
|| (curMapEntry.getValue() == null)) {
continue;
}

Method curMethod = curMapEntry.getKey();

Attribute curAttrAnnotation = null;
Text curTextAnnotation = null;

if (curMapEntry.getValue() instanceof Attribute) {
curAttrAnnotation = (Attribute) curMapEntry.getValue();
} else if (curMapEntry.getValue() instanceof Text) {
curTextAnnotation = (Text) curMapEntry.getValue();
} else {
continue;
}

String curValue = null;
try {
// Try to invoke the getter
curValue = (String) curMethod.invoke(curRequest);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {

// The getter method seems to need any argument, strange! Skip
// this!
continue;
}

// If the method has an Attribute annotation, then ...
if (curAttrAnnotation != null) {
boolean curAttrRequired = curAttrAnnotation.required();
String curAttrName = curAttrAnnotation.name();

/*
* IF the returned method value is NULL THEN IF if the attribute
* is required THEN throw a NullPointerException, ELSE skip the
* attribute
*/
if (curValue == null) {
if (curAttrRequired) {
throw new NullPointerException(
"The required attribute " + curAttrName
+ " returned NULL!");
} else {
continue;
}
}

// The attribute will be added as XML text now
curNode.setAttribute(curAttrName, curValue);
} else
// If the method has a Text annotation, then ...
if (curTextAnnotation != null) {
// we only need to store it for later string creation
curNode.setValue(curValue);
}
}

curNode.commit();
}
}

基于这个类,我创建了 - 例如 - 类 SetRequestListConverter .它实现了 Simple 的 Converter接口(interface),所以它提供了方法 read未实现和 write它获取可能包含元素或可能为空的列表。

该示例显示了类 SetRequestList 的转换器的实现。 .它扩展了之前介绍的基础 RequestConverter类并实现 Converter输入 SetRequestList .

public class SetRequestListConverter extends RequestListConverter implements Converter<SetRequestList> {

@Override
public SetRequestList read(InputNode newNode) throws Exception {
return null;
}

@Override
public void write(OutputNode newNode, SetRequestList newValue) throws Exception {
if (newValue.requests.isEmpty()) {
newNode.setValue("");
return;
}

this.prepareMethodList(SetRequest.class);

/*
* Now we can go through all SetRequests and call the methods
* to build the XML attributes and to get the element value (i.e. parameters)
*/

for (SetRequest curRequest : newValue.requests) {
OutputNode curNode = newNode.getChild("set");

this.writeRequest(curNode, curRequest);
}
}
}

使用过的 SetRequestList是一个包含 ArrayList<SetRequest> 的简单类.这是为了隐藏这实际上是一个 ArrayList 的事实。
@Root
@Convert(SetRequestListConverter.class)
public abstract class SetRequestList {
protected ArrayList<SetRequest> requests = new ArrayList<SetRequest>();

public void add(T newRequest) {
requests.add(newRequest);
}
}

然后可以像这样使用这个类:
public class ClassToSerialize {
private SetRequestList requestedSets = new SetRequestList();

@Element(name="get", required=true)
public SetRequestList getRequestedSets() {
return requestedSets;
}

@Element(name="get", required=true)
public void setRequestedSets(SetRequestList newRequestedSets) {
requestedSets = newRequestedSets;
}
}
SetRequestList 生成的 XML包含元素将如下所示:
<get>
<set someAttribute="text" anotherAttribute="bla">Some Text</set>
...
</get>
SetRequestList 生成的 XML为空将如下所示:
<get></get>

是的,这正是我所需要的,而且我可以继续使用 SetRequest 中的注释。或任何类(class)!无需再次(重新)定义 XML 结构!

Simple 的代码建议

关注:这只是一个解决方案,未经测试!

我查看了Simple的源代码,发现 Formatter class 实际上是在编写开始和结束标记,以及空元素标记。它是通过移交 Format 创建的。目的。 Simple 的 Javadoc 描述了 Format类如下:

The Format object is used to provide information on how a generated XML document should be structured.



因此,如果应该创建空元素标签,则可以使用信息对其进行扩展。为此,我添加了私有(private)变量 useEmptyEndTag以及适当的 getter 和 setter 方法。变量将被初始化为 true在构造函数内部。如果空结束标签样式不是应该创建的,可以在创建 Format后设置对象使用 myFormat.setUseEmptyEndTag(false) .
Formatter类通过一个新的私有(private)变量来增强,该变量包含给定的 Format对象,以便能够在适当的代码位置访问设置的参数。空的结束标签写在 writeEnd 里面.有看官方源代码才能看到原始代码。这是我的建议是避免空元素标签:
public void writeEnd(String name, String prefix) throws Exception {
String text = indenter.pop();

// This will act like the element contains text
if ((last == Tag.START) && (!format.isUseEmptyEndTag())) {
write('>');
last = Tag.TEXT;
}

if (last == Tag.START) {
write('/');
write('>');
} else {
if (last != Tag.TEXT) {
write(text);
}
if (last != Tag.START) {
write('<');
write('/');
write(name, prefix);
write('>');
}
}
last = Tag.END;
}

这个提议是更好的解决方案——在我看来——我希望它会被添加到 Simple 的源代码中。

最佳答案

正如 baraky 之前所写,您可以使用 <rpc></rpc> 解决该部分。带有转换器的标签,如下所示:Prevent inclusion of empty tag for an empty ElementList in an ElementListUnion .ExampleConverter上有评论这个特殊部分在哪里完成。

此外获得name属性见这里:How do you access field annotations from a custom Converter with Simple?

所以你需要的是一个Converter - 为您的类(class)实现。对于类型(intString 等),请查看 Transformer -类(class)。

关于java - 避免简单框架输出中的空元素标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14955902/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com