替换javax中的值。json。JsonObject不能直接使用,因为javax。json。JsonObject实现了一个不可变的映射。为了做到这一点,您必须创建一个新的JsonObject,并将值从原来的JsonObject复制到新的JsonObject中,同时替换要替换的值。我找到了如何使用“简单”JsonObject实现这一点的示例,其中没有嵌套的JsonObject。我要寻找的是一个通用的replace实现,其中传递一个JsonObject、属性名和新值。这个方法应该“遍历”JsonObject并替换属性(无论它在对象层次结构中的何处),而保持其他属性不变。例如,这是我最初的JsonObject
{
"Attr1":number1,
"Attr2":number2,
"Attr3":number3,
"Attr4":[
"string1"
],
"Attr5":[
{
"Attr6":[
{
"Attr7":"string2",
"Attr8":"string3",
"$Attr9":number4
},
{
"Attr7":"string4",
"Attr8":"string5",
"Attr9":number5
}
],
"Attr10":number6,
"Attr14":{
"Attr10":"string6",
"Attr11":"string7",
"Attr12":"string8"
},
"Attr13":[
"string9",
"string10"
],
"Attr14":"string11"
}
]
}
我想用一个字符串数组代替Attr6,而不是JsonObject数组:
"Attr6":["newString1","newString2"],
相应的调用可能类似于replaceValue(JsonObject jObj,String attrName,JsonValue newValue)),其中“jObj”是整个Json,“attrName”是“Attr6”,而“newValue”是包含这两个字符串的JsonArray。
有人能给我举一个实现这样一个功能的例子吗,或者帮我解决这个问题吗?
我自己尝试过这个方法,但它并没有真正起作用,因为构建器是在每次递归迭代中重新创建的(或者更可能是因为它完全错了…:)
public static JsonObject replaceValue( final JsonObject jsonObject, final String jsonKey, final JsonValue jsonValue )
{
JsonObjectBuilder builder = Json.createObjectBuilder();
if(jsonObject == null)
{
return builder.build();
}
Iterator<Entry<String, JsonValue>> it = jsonObject.entrySet().iterator();
while (it.hasNext())
{
@SuppressWarnings( "rawtypes" )
JsonObject.Entry mapEntry = it.next();
if (mapEntry.getKey() == jsonKey)
{
builder.add(jsonKey, jsonValue);
}
else if (ValueType.STRING.equals(((JsonValue) mapEntry.getValue()).getValueType()) || ValueType.NUMBER.equals(((JsonValue) mapEntry.getValue()).getValueType()) || ValueType.TRUE.equals(((JsonValue) mapEntry.getValue()).getValueType()) ||
ValueType.FALSE.equals(((JsonValue) mapEntry.getValue()).getValueType()) || (JsonValue) mapEntry.getValue() == null || "schemas".equalsIgnoreCase((String) mapEntry.getKey()))
{
builder.add(mapEntry.getKey().toString(), (JsonValue) mapEntry.getValue());
}
else if (ValueType.OBJECT.equals(((JsonValue) mapEntry.getValue()).getValueType()))
{
JsonObject modifiedJsonobject = (JsonObject) mapEntry.getValue();
if (modifiedJsonobject != null)
{
replaceValue(modifiedJsonobject, jsonKey, jsonValue);
}
}
else if (ValueType.ARRAY.equals(((JsonValue) mapEntry.getValue()).getValueType()))
{
for (int i = 0; i < ((JsonValue) mapEntry.getValue()).asJsonArray().size(); i++)
{
replaceValue((JsonObject) ((JsonValue) mapEntry.getValue()).asJsonArray().get(i), jsonKey, jsonValue);
}
}
}
return builder.build();
}
如果您不想使用流式API(正如我在另一个答案中所使用的那样),我认为您可以实现一种更紧凑的方法,与您的方法类似,使用JsonObjectBuilder和JSONOArayBuilder,以及递归:
private static JsonStructure iterate(final JsonStructure json) {
if (json.getValueType().equals(ValueType.OBJECT)) {
JsonObjectBuilder builder = Json.createObjectBuilder();
json.asJsonObject().forEach((key, value) -> {
switch (value.getValueType()) {
case OBJECT:
if (key.equals(targetKey)) {
builder.add(key, replacementJson);
} else {
builder.add(key, iterate(value.asJsonObject()));
} break;
case ARRAY:
if (key.equals(targetKey)) {
builder.add(key, replacementJson);
} else {
builder.add(key, iterate(value.asJsonArray()));
} break;
default:
if (key.equals(targetKey)) {
builder.add(key, replacementJson);
} else {
builder.add(key, value);
} break;
}
});
return builder.build();
} else if (json.getValueType().equals(ValueType.ARRAY)) {
JsonArrayBuilder builder = Json.createArrayBuilder();
json.asJsonArray().forEach((value) -> {
switch (value.getValueType()) {
case OBJECT:
builder.add(iterate(value.asJsonObject()));
break;
case ARRAY:
builder.add(iterate(value.asJsonArray()));
break;
default:
builder.add(value);
break;
}
});
return builder.build();
}
return null;
}
就我个人而言,阅读这个递归代码比阅读我另一个答案中的流代码更难。但它肯定更简洁。
它的工作原理是向下迭代每个JSON对象和数组的嵌套级别,然后从最深的嵌套级别向外构建原始数据的副本。当它找到指定的替换键时,它使用相关的替换JSON作为键的值。
可以按如下方式调用上述方法-它可以很好地打印最终结果:
java prettyprint-override">final JsonStructure jsonOriginal = Json.createReader(new StringReader(JSONSTRING)).readObject();
final JsonStructure jsonCopy = iterate(jsonOriginal);
Map<String, Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
String jsonString;
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
try ( Writer writer = new StringWriter()) {
writerFactory.createWriter(writer).write(jsonCopy);
jsonString = writer.toString();
}
System.out.println(jsonString);
对于我的替代JSON,我使用了这个,显示了一些测试数据示例:
private final static String targetKey = "Attr6";
//private final static JsonStructure replacementJson = Json.createArrayBuilder()
// .add("newString1")
// .add("newString2").build();
private final static JsonStructure replacementJson = Json.createObjectBuilder()
.add("newkey1", "newString1")
.add("newkey2", "newString2").build();
因此,使用与我的另一个答案相同的起始JSON,此代码生成以下内容:
{
"Attr0": null,
"Attr1": true,
"Attr2": false,
"Attr3": 3,
"Attr4": [
"string1"
],
"Attr5": [
{
"Attr6": {
"newkey1": "newString1",
"newkey2": "newString2"
},
"Attr10": 6,
"Attr14": {
"Attr10": "string6",
"Attr11": "string7",
"Attr12": "string8"
},
"Attr13": [
"string9",
123.45,
false
],
"Attr15": "string11"
}
]
}
从Kolban在本文中的回答中获得线索后,将JSON字符串转换为HashMap,我应该找到一个解决方案:
public class JsonUtils
{
public static JsonObject replaceValue( final JsonObject jsonObject, final String jsonKey, final Object jsonValue )
{
JsonObjectBuilder builder = Json.createObjectBuilder();
if (jsonObject != JsonObject.NULL)
{
builder = replace(jsonObject, jsonKey, jsonValue, builder);
}
return builder.build();
}
private static JsonObjectBuilder replace( final JsonObject jsonObject, final String jsonKey, final Object jsonValue, final JsonObjectBuilder builder )
{
Iterator<Entry<String, JsonValue>> it = jsonObject.entrySet().iterator();
while (it.hasNext())
{
@SuppressWarnings( "rawtypes" )
JsonObject.Entry mapEntry = it.next();
String key = mapEntry.getKey().toString();
Object value = mapEntry.getValue();
if (key.equalsIgnoreCase(jsonKey))
{
if (jsonValue instanceof String)
{
builder.add(jsonKey, (String) jsonValue);
}
else
{
builder.add(jsonKey, (JsonValue) jsonValue);
}
// here you can add the missing casting you need
continue;
}
if (value instanceof JsonArray)
{
value = toJsonArray((JsonArray) value, jsonKey, jsonValue, builder);
}
else if (value instanceof JsonObject)
{
JsonObjectBuilder newBuilder = Json.createObjectBuilder();
value = replace((JsonObject) value, jsonKey, jsonValue, newBuilder);
if (value instanceof JsonObjectBuilder)
{
value = ((JsonObjectBuilder) value).build();
}
}
builder.add(key, (JsonValue) value);
}
return builder;
}
private static JsonArray toJsonArray( final JsonArray array, final String jsonKey, final Object jsonValue, final JsonObjectBuilder builder )
{
JsonArrayBuilder jArray = Json.createArrayBuilder();
for (int i = 0; i < array.size(); i++)
{
Object value = array.get(i);
if (value instanceof JsonArray)
{
value = toJsonArray((JsonArray) value, jsonKey, jsonValue, builder);
}
else if (value instanceof JsonObject)
{
JsonObjectBuilder newBuilder = Json.createObjectBuilder();
value = replace((JsonObject) value, jsonKey, jsonValue, newBuilder);
if (value instanceof JsonObjectBuilder)
{
value = ((JsonObjectBuilder) value).build();
}
}
jArray.add((JsonValue) value);
}
return jArray.build();
}
请记住,如果要替换的键在整个JsonObject中是唯一的,那么这是可行的。
任何改进都是值得赞赏的。。。
这是解决问题的另一种方法,它使用由javax.json.stream.JsonParser
提供的流解析器。这会从JSON源代码生成一个令牌流,使用javax.json.stream.JsonParser。事件
值来描述令牌的类型(例如START_OBJECT
、KEY_NAME
等等)。
对我们来说最重要的是,解析器上有skipObject()
和skipArray()
方法,它们允许我们删除源JSON中不需要的部分。
总体方法是构建一个新版本的JSON,逐个令牌,作为一个字符串,当我们到达JSON中的相关位置(或多个位置)时替换部分。
最后,我们将新字符串转换回一个对象,以便可以很好地打印它。
这种方法中没有使用递归。
import java.io.IOException;
import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.json.JsonObject;
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;
public class StreamDemo {
public static void doStream() throws IOException {
JsonParser jsonParser = Json.createParser(new StringReader(JSONSTRING));
StringBuilder sb = new StringBuilder();
Event previous = null;
String targetKeyName = "Attr6";
String replacement = "[\"newString1\",\"newString2\"]";
// This event reflects the end of the "replacement" string - namely "]".
// We need this because this event may be different from the replaced event.
Event replacementPreviousEvent = Event.END_ARRAY;
// Used when we find the target key for replacement:
boolean doReplacement = false;
while (jsonParser.hasNext()) {
Event event = jsonParser.next();
if (doReplacement) {
// Skip over the structure we want to replace:
if (event.equals(Event.START_OBJECT)) {
jsonParser.skipObject();
} else if (event.equals(Event.START_ARRAY)) {
jsonParser.skipArray();
}
// Write the replacement fragment here:
sb.append(replacement);
// Move to the next event in the stream:
event = jsonParser.next();
previous = replacementPreviousEvent;
doReplacement = false;
}
if (Event.KEY_NAME.equals(event)
&& jsonParser.getString().equals(targetKeyName)) {
doReplacement = true;
}
switch (event) {
case START_OBJECT:
if (Event.END_OBJECT.equals(previous)) {
sb.append(",");
}
sb.append("{");
break;
case END_OBJECT:
sb.append("}");
break;
case START_ARRAY:
sb.append("[");
break;
case END_ARRAY:
sb.append("]");
break;
case KEY_NAME:
sb = previousWasAValue(previous, sb);
sb = previousWasAnEnd(previous, sb);
sb.append("\"").append(jsonParser.getString()).append("\":");
break;
case VALUE_STRING:
sb = previousWasAValue(previous, sb);
sb.append("\"").append(jsonParser.getString()).append("\"");
break;
case VALUE_NUMBER:
sb = previousWasAValue(previous, sb);
if (jsonParser.isIntegralNumber()) {
sb.append(jsonParser.getLong());
} else {
sb.append(jsonParser.getBigDecimal().toPlainString());
}
break;
case VALUE_TRUE:
sb = previousWasAValue(previous, sb);
sb.append("true");
break;
case VALUE_FALSE:
sb = previousWasAValue(previous, sb);
sb.append("false");
break;
case VALUE_NULL:
sb = previousWasAValue(previous, sb);
sb.append("null");
break;
default:
break;
}
previous = event;
}
// At the end, pretty-print the new JSON:
JsonObject modifiedObject = Json.createReader(new StringReader(sb.toString())).readObject();
Map<String, Boolean> config = new HashMap<>();
config.put(JsonGenerator.PRETTY_PRINTING, true);
String jsonString;
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
try ( Writer writer = new StringWriter()) {
writerFactory.createWriter(writer).write(modifiedObject);
jsonString = writer.toString();
}
System.out.println(jsonString);
}
private static StringBuilder previousWasAValue(Event previous, StringBuilder sb) {
// The current value follows another value - so a separating comma is needed:
if (Event.VALUE_STRING.equals(previous)
|| Event.VALUE_NUMBER.equals(previous)
|| Event.VALUE_TRUE.equals(previous)
|| Event.VALUE_FALSE.equals(previous)
|| Event.VALUE_NULL.equals(previous)) {
sb.append(",");
}
return sb;
}
private static StringBuilder previousWasAnEnd(Event previous, StringBuilder sb) {
// The current key follows the end of an object or an array, so a
// separating comma is needed:
if (Event.END_OBJECT.equals(previous)
|| Event.END_ARRAY.equals(previous)) {
sb.append(",");
}
return sb;
}
private static final String JSONSTRING
= """
{
"Attr0": null,
"Attr1": true,
"Attr2": false,
"Attr3": 3,
"Attr4": [
"string1"
],
"Attr5": [{
"Attr6": [{
"Attr7": "string2",
"Attr8": "string3",
"Attr9": 4
},
{
"Attr7": "string4",
"Attr8": "string5",
"Attr9": 5
}
],
"Attr10": 6,
"Attr14": {
"Attr10": "string6",
"Attr11": "string7",
"Attr12": "string8"
},
"Attr13": [
"string9",
123.45,
false
],
"Attr15": "string11"
}]
}
""";
}
主要内容:1 简单JSON与JSONObject的转换,2 JSON数组与JSONArray的转换,3 复杂JSON与JSONObject的转换1 简单JSON与JSONObject的转换 1.1 简单JSON转为JSONObject MainApp: 运行效果为: 1.2 JSONObject转为简单JSON MainApp: 运行效果为: 2 JSON数组与JSONArray的转换 2.1 JSON数组转为JSONArray MainApp: 运行效果为: 2.2 JSONArray转为JS
在开始新的Jakarta(9)项目时,我需要使用“javax”JSON-P API处理旧的(遗留库和模块)。通常我们以这个错误结束: java:不兼容类型:jakarta。json。JsonObject无法转换为javax。json。JsonObject公司 不幸的是,旧代码使用了各种javax。json。*类,尤其是JsonObject,这些类在新模块的方法中不可用(因为它们使用的是jakart
我们有这样一个json字符串: 我们想使用下面的代码来替换后一个key6的值: 但是由于key6在jsonstring中显示了两次,我们替换了错误的值。上面的json结构只是一个例子,“key6”的json路径在不同的json中是完全不同的。我们无法为这种替换编写确切的jsonpath。我们怎么能只是用java替换没有孩子的“key6”的值?多谢了。
问题内容: 我正在使用Eclipse IDE,并且正在编写servlet。Servlet应该接受html文件中的值,并相应地返回JSON响应。 我的doPost()是: 当我在Eclipse中运行此servlet时,会出现一个文件下载对话框。 当使用Tomcat在Eclipse外部运行时,出现错误: 行Server1.doPost(Server1.java:25)指的是 我已经将org.json.
介绍 JSONObject代表一个JSON中的键值对象,这个对象以大括号包围,每个键值对使用,隔开,键与值使用:隔开,一个JSONObject类似于这样: { "key1":"value1", "key2":"value2" } 此处键部分可以省略双引号,值为字符串时不能省略,为数字或波尔值时不加双引号。 使用 创建 JSONObject json1 = JSONUtil.createO