当元素可以使用不同的类型时,如何创建JSON数据结构

时间:2018-01-31 11:48:44

标签: java gson

在此question中,我们看到子元素可以是其他数据项的数组,也可以是布尔值

我使用Java创建数据,存储在Data类中,然后使用Google Gson转换为Json。但是因为孩子可以是两个不同的东西,我通过在我的数据中使用变量 kids 来代表这一点,当我需要存储为boolean时,我会使用它。然后在生成的json上执行String替换,将其转换为子元素。

但是这个hack不是很令人满意和有问题(即如果他们有内容“孩子”的真实数据)那么用不同数据类型表示数据的正确方法是什么。

public class Data
{
    private String id;
    private String text;
    private String icon;
    private State  state;
    private boolean kids;

    private List<Data> children = null;

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getText()
    {
        return text;
    }

    public void setText(String text)
    {
        this.text = text;
    }

    public String getIcon()
    {
        return icon;
    }

    public void setIcon(String icon)
    {
        this.icon = icon;
    }

    public List<Data> getChildren()
    {
        return children;
    }

    public void setChildren(List<Data> children)
    {
        this.children = children;
    }

    public State getState()
    {
        return state;
    }

    public void setState(State state)
    {
        this.state = state;
    }

    public boolean getKids()
    {
        return kids;
    }

    public void setKids(boolean kids)
    {
        this.kids = kids;
    }
}

public static String createFolderJsonData()
{
  CreateFolderTree cft = new CreateFolderTree(null);
  String treeData = cft.start(1).replace("kids", "children");
  return treeData;
}

2 个答案:

答案 0 :(得分:1)

假设您知道孩子的类型,您可以像这样解决它

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.org/ui"
	xmlns:pe="http://primefaces.org/ui/extensions"
	xmlns:sec="http://www.springframework.org/security/tags"
	xmlns:f="http://java.sun.com/jsf/core"
	template="/WEB-INF/template.xhtml">

	<ui:define name="subheader">
        Page Header
    </ui:define>

	<ui:define name="head">
		<style>
.ui-panelgrid .ui-panelgrid-cell {
	border: none !important;
}

.ui-panelgrid {
	border: none !important;
}

.ui-timepicker-div {
	background: #f7f5f3;
	border: 1px solid #cecece;
	border-radius: 10px;
	margin-top: -47px;
	margin-left: 49px;
	margin-right: -75px;
	margin-left: 49px;
}
.preformatted {
    white-space: pre-wrap;
}
</style>

	</ui:define>

	<ui:define name="body">

		<div class="Container100">
			<div class="ContainerIndent">
				<h:form>
					<p:breadCrumb>
						<p:menuitem value="index" url="../../../../index.xhtml" />
						<p:menuitem value="page" url="page.xhtml" />
					</p:breadCrumb>
				</h:form>
			</div>
		</div>

		<div class="divshadow">

			<div class="Container100">
				<div class="ContainerIndent">
					<div class="Card">
						<div class="CardTopic">
							page 
							<h:form>
              content of my page
              </h:form>
 	</ui:define>
</ui:composition>

现在打印出正确的内容,请注意public class Data<T>{ private T children = null; public T getChildren(){ return children; } public void setChildren(T children){ this.children = children; } } public class DataRunner { public static void main(String[] args){ Data<List<Data>> data = new Data<>(); Data<List<Data>> subDataOne = new Data<>(); subDataOne.setChildren(new ArrayList<>()); Data<Boolean> subDataTwo = new Data<>(); subDataTwo.setChildren(true); List<Data> listData = new ArrayList<>(); listData.add(subDataOne); listData.add(subDataTwo); data.setChildren(listData); // {"children":[{"children":[]},{"children":true}]} System.out.println(new Gson().toJson(data)); } } 并不关心泛型类型ArrayList

答案 1 :(得分:0)

对于反序列化:

您必须创建两个类,一个用于Boolean类型(我将其命名为BoolData),另一个用于List<Data>类型(ListData)。 然后,您可以编写一个自定义JsonDeserializer,将对象反序列化为BoolDataListData,使用JSON值确定要使用的类型。

型号:

public abstract class Data<T> {

    private String id;

    private T children;

    // ...
    public Data() {
    }

    public String getId() {
        return id;
    }

    public T getChildren() {
        return children;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setChildren(T children) {
        this.children = children;
    }

    @Override
    public String toString() {
        return "Data{" + "id=" + id + ", children=" + children + '}';
    }
}

public class ListData extends Data<List<Data<?>>> {
}

public class BoolData extends Data<Boolean> {
}

反序列化程序:

String json = ""
        + "["
        + "  {"
        + "    \"id\": \"1\""
        + "  },"
        + "  {"
        + "    \"id\": \"2\","
        + "    \"children\": ["
        + "       {"
        + "         \"id\": \"2.1\","
        + "         \"children\": true"
        + "       },"
        + "       {"
        + "         \"id\": \"2.2\","
        + "         \"children\": []"
        + "       }"
        + "    ]"
        + "  }"
        + "]";
    List<Data<?>> data = new GsonBuilder()
        .registerTypeAdapter(Data.class, (JsonDeserializer<Data<?>>) (elem, type, ctx) -> {
            JsonObject obj = elem.getAsJsonObject();
            JsonElement children = obj.get("children");

            // If "children" is a boolean, deserialize it as BoolData
            return children != null && children.isJsonPrimitive() && children.getAsJsonPrimitive().isBoolean()
                ? ctx.deserialize(elem, BoolData.class)
                : ctx.deserialize(elem, ListData.class);
        })
        .create()
        .fromJson(json, new TypeToken<List<Data<?>>>() {
        }.getType());
    System.out.println(data);

输出

[Data{id=1, children=null}, Data{id=2, children=[Data{id=2.1, children=true}, Data{id=2.2, children=[]}]}]

使用JSON:

[
    {
        "id": "1"
    },
    {
        "id": "2",
        "children": [
            {
                "id": "2.1",
                "children": true
            }, {
                "id": "2.2",
                "children": []
            }
        ]
    }
]