Я использую предоставленную здесь библиотеку JSON http://www.json.org/java/index.html для преобразования имеющейся у меня строки json в CSV. Но у меня проблема в том, что порядок ключей теряется после преобразования.
Это код преобразования:
JSONObject jo = new JSONObject(someString);
JSONArray ja = jo.getJSONArray("items");
String s = CDL.toString(ja);
System.out.println(s);
Это содержимое someString:
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
]
}
Вот результат:
WO,QU,WR,QA,NO
hasd,asd,qwe,end,qwer
В то время как я ожидаю сохранить порядок ключей:
WR,QU,QA,WO,NO
qwe,asd,end,hasd,qwer
Могу ли я получить такой результат с помощью этой библиотеки? Если нет, существует ли какая-либо другая библиотека, которая предоставит возможность сохранять порядок ключей в результате?
foo
перед ключом,bar
а иногда иbar
раньшеfoo
. Это затрудняет написание тестов для.Ответы:
Есть (хакерские) способы сделать это ... но вы не должны.
В JSON объект определяется так:
См. Http://json.org .
Большинство реализаций JSON не прилагают никаких усилий для сохранения порядка пар имя / значение объекта, поскольку он (по определению) не имеет значения.
Если вы хотите сохранить порядок, вам необходимо переопределить структуру данных; например
{ "items": [ [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ], ] }
или проще:
{ "items": [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ] }
СЛЕДОВАТЬ ЗА
Вам нужно вести жесткий разговор с тем, кто разработал эту файловую структуру, и не позволит вам ее изменить. Это / они совершенно неправы. Вам нужно их убедить.
Если они действительно не позволят вам это изменить:
Такие вещи очень плохие. С одной стороны, ваше программное обеспечение будет нарушать устоявшуюся / давнюю спецификацию, разработанную для обеспечения взаимодействия. С другой стороны, придурки, которые разработали этот убогий (не JSON!) Формат файла, вероятно, шлёпают чужие системы и т. Д., Потому что системы не могут справиться с их ерундой.
ОБНОВИТЬ
Также стоит прочитать, что говорится в JSON RFC (RFC 7159) по этому поводу. Вот несколько выдержек:
источник
Поддерживать порядок довольно просто. У меня была такая же проблема с поддержанием порядка от уровня БД до уровня пользовательского интерфейса.
Откройте файл JSONObject.java. Он внутренне использует HashMap, который не поддерживает порядок.
Измените его на LinkedHashMap:
//this.map = new HashMap(); this.map = new LinkedHashMap();
Это сработало для меня. Дай мне знать в комментариях. Я предлагаю, чтобы сама библиотека JSON имела еще один класс JSONObject, который поддерживает порядок, например JSONOrderdObject.java. Я очень плохо выбираю имена.
источник
this.map = new LinkedHashMap<String, Object>();
все еще не работает. Пожалуйста помоги ?JSONObject.java
берет любую карту, которую вы проходите. Это может бытьLinkedHashMap
илиTreeMap
потребуетсяhashmap
только тогда, когда карта пуста.Вот конструктор
JSONObject.java
класса, который будет проверять карту.public JSONObject(Map paramMap) { this.map = (paramMap == null ? new HashMap() : paramMap); }
Итак, прежде чем создать конструкцию объекта json
LinkedHashMap
и затем передать ее конструктору следующим образом,LinkedHashMap<String, String> jsonOrderedMap = new LinkedHashMap<String, String>(); jsonOrderedMap.put("1","red"); jsonOrderedMap.put("2","blue"); jsonOrderedMap.put("3","green"); JSONObject orderedJson = new JSONObject(jsonOrderedMap); JSONArray jsonArray = new JSONArray(Arrays.asList(orderedJson)); System.out.println("Ordered JSON Fianl CSV :: "+CDL.toString(jsonArray));
Так что менять
JSONObject.java
класс не нужно . Надеюсь, это кому-то поможет.источник
JSONObject
он не заказан как мойLinkedHashMap
. Вы пользуетесьorg.json
библиотекой?org.json
тот ... Он определяетHashMap
внутренне, что быMap
вы ему ни дали: @Deepak, вы можете указать нам на реализацию, которую вы использовали?org.json
библиотекой. Когда вы создаете новыйJSONObject
объект, передавая карту в качестве аргумента, он всегда будет преобразован вHashMap
. Конструктор сначала создает новую карту:,this.map = new HashMap<String, Object>();
а затем перебирает вашу карту, копируя каждый элемент в свойHashMap
.Более подробное, но широко применимое решение такого рода проблем состоит в использовании пары структур данных: списка, содержащего упорядочение, и карты, содержащей отношения.
Например:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ], "itemOrder": ["WR", "QU", "QA", "WO", "NO"] }
Вы перебираете список itemOrder и используете его для поиска значений карты. Порядок сохраняется, без клуджей.
Я использовал этот метод много раз.
источник
Еще одно хакерское решение с использованием рефлекса:
JSONObject json = new JSONObject(); Field map = json.getClass().getDeclaredField("map"); map.setAccessible(true);//because the field is private final... map.set(json, new LinkedHashMap<>()); map.setAccessible(false);//return flag
источник
Apache Wink имеет OrderedJSONObject . Он сохраняет порядок при анализе строки.
источник
Просто наткнулся на ту же проблему, я считаю, что окончательное решение, используемое автором, заключалось в использовании настраиваемого ContainerFactory:
public static Values parseJSONToMap(String msgData) { JSONParser parser = new JSONParser(); ContainerFactory containerFactory = new ContainerFactory(){ @Override public Map createObjectContainer() { return new LinkedHashMap(); } @Override public List creatArrayContainer() { return null; } }; try { return (Map<String,Object>)parser.parse(msgData, containerFactory); } catch (ParseException e) { log.warn("Exception parsing JSON string {}", msgData, e); } return null; }
см. http://juliusdavies.ca/json-simple-1.1.1-javadocs/org/json/simple/parser/JSONParser.html#parse(java.io.Reader,org.json.simple.parser.ContainerFactory)
источник
Решено.
Я использовал библиотеку JSON.simple отсюда https://code.google.com/p/json-simple/, чтобы прочитать строку JSON, чтобы сохранить порядок ключей и использовать библиотеку JavaCSV отсюда http://sourceforge.net/ projects / javacsv / для преобразования в формат CSV.
источник
org.json
чтобы преобразовать ,List<LinkedHahMap>
чтобыJSONArray
для того , чтобы создатьCSV
, тоCSV
создается , но не в том же порядке , как и моиList
. Я попытался использовать две библиотеки, которые вы здесь представляете, но мне не удалось найти методы для преобразования в.CSV
Не могли бы вы дать более подробную информацию.Я знаю, что это решено, и вопрос был задан давно, но поскольку я имею дело с аналогичной проблемой, я хотел бы дать к этому совершенно другой подход:
Для массивов сказано: «Массив - это упорядоченный набор значений». на http://www.json.org/ - но объекты («Объект - это неупорядоченный набор пар имя / значение.») не упорядочены.
Интересно, почему этот объект находится в массиве - это подразумевает порядок, которого там нет.
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ] }
Поэтому решением было бы поместить ключи в «настоящий» массив и добавить данные в виде объектов к каждому ключу следующим образом:
{ "items": [ {"WR": {"data": "qwe"}}, {"QU": {"data": "asd"}}, {"QA": {"data": "end"}}, {"WO": {"data": "hasd"}}, {"NO": {"data": "qwer"}} ] }
Таким образом, это подход, который пытается переосмыслить исходное моделирование и его цель. Но я не тестировал (и мне интересно), сохранят ли все задействованные инструменты порядок этого исходного массива JSON.
источник
В реальном мире приложение почти всегда будет иметь компонент или домен java, которые необходимо сериализовать / десериализовать в / из JSON. Уже упоминалось, что спецификация объекта JSON не гарантирует порядок, и любые манипуляции с этим поведением не оправдывают требования. У меня был тот же сценарий в моем приложении, где мне нужно было сохранить порядок только для удобства чтения. Я использовал стандартный способ Джексона для сериализации моего java-компонента в JSON:
Object object = getObject(); //the source java bean that needs conversion String jsonString = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object);
Чтобы создать json с упорядоченным набором элементов, я просто использую аннотацию свойств JSON в Java-компоненте, который я использовал для преобразования. Пример ниже:
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"name","phone","city","id"}) public class SampleBean implements Serializable { private int id; private String name: private String city; private String phone; //...standard getters and setters }
getObject (), использованный выше:
public SampleBean getObject(){ SampleBean bean = new SampleBean(); bean.setId("100"); bean.setName("SomeName"); bean.setCity("SomeCity"); bean.setPhone("1234567890"); return bean; }
Вывод отображается в соответствии с аннотацией порядка свойств Json:
{ name: "SomeName", phone: "1234567890", city: "SomeCity", id: 100 }
источник
Самый безопасный способ - это, вероятно, переопределить метод ключей, который используется для генерации вывода:
new JSONObject(){ @Override public Iterator keys(){ TreeSet<Object> sortedKeys = new TreeSet<Object>(); Iterator keys = super.keys(); while(keys.hasNext()){ sortedKeys.add(keys.next()); } return sortedKeys.iterator(); } };
источник
patchFor (ответ @gary):
$ git diff JSONObject.java diff --git a/JSONObject.java b/JSONObject.java index e28c9cd..e12b7a0 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -32,7 +32,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Enumeration; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; @@ -152,7 +152,9 @@ public class JSONObject { * Construct an empty JSONObject. */ public JSONObject() { - this.map = new HashMap<String, Object>(); +// this.map = new HashMap<String, Object>(); + // I want to keep order of the given data: + this.map = new LinkedHashMap<String, Object>(); } /** @@ -243,7 +245,7 @@ public class JSONObject { * @throws JSONException */ public JSONObject(Map<String, Object> map) { - this.map = new HashMap<String, Object>(); + this.map = new LinkedHashMap<String, Object>(); if (map != null) { Iterator<Entry<String, Object>> i = map.entrySet().iterator(); while (i.hasNext()) {
источник
Вы можете использовать следующий код, чтобы выполнить заказную сериализацию ORDERED и десериализацию массива JSON (в этом примере предполагается, что вы заказываете строки, но его можно применить ко всем типам):
Сериализация
JSONArray params = new JSONArray(); int paramIndex = 0; for (String currParam : mParams) { JSONObject paramObject = new JSONObject(); paramObject.put("index", paramIndex); paramObject.put("value", currParam); params.put(paramObject); ++paramIndex; } json.put("orderedArray", params);
Десериализация
JSONArray paramsJsonArray = json.optJSONArray("orderedArray"); if (null != paramsJsonArray) { ArrayList<String> paramsArr = new ArrayList<>(); for (int i = 0; i < paramsJsonArray.length(); i++) { JSONObject param = paramsJsonArray.optJSONObject(i); if (null != param) { int paramIndex = param.optInt("index", -1); String paramValue = param.optString("value", null); if (paramIndex > -1 && null != paramValue) { paramsArr.add(paramIndex, paramValue); } } } }
источник
Ваш пример:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ] }
добавить элемент "itemorder"
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ], "itemorder":["WR","QU","QA","WO","NO"] }
Этот код генерирует желаемый результат без строки заголовка столбца:
JSONObject output = new JSONObject(json); JSONArray docs = output.getJSONArray("data"); JSONArray names = output.getJSONArray("itemOrder"); String csv = CDL.toString(names,docs);
источник
вместо использования jsonObject попробуйте использовать CsvSchema по-своему и напрямую преобразует объект в csv
и он содержит идентификатор заказа, в котором в вашем pojo есть @JsonPropertyOrder
источник
Underscore-java сохраняет заказы для элементов при чтении json. Я сопровождаю проект.
String json = "{\n" + " \"items\":\n" + " [\n" + " {\n" + " \"WR\":\"qwe\",\n" + " \"QU\":\"asd\",\n" + " \"QA\":\"end\",\n" + " \"WO\":\"hasd\",\n" + " \"NO\":\"qwer\"\n" + " }\n" + " ]\n" + "}"; System.out.println(U.fromJson(json)); // {items=[{WR=qwe, QU=asd, QA=end, WO=hasd, NO=qwer}]}
источник
Протестировал решение подмигивания и работает нормально:
@Test public void testJSONObject() { JSONObject jsonObject = new JSONObject(); jsonObject.put("bbb", "xxx"); jsonObject.put("ccc", "xxx"); jsonObject.put("aaa", "xxx"); jsonObject.put("xxx", "xxx"); System.out.println(jsonObject.toString()); assertTrue(jsonObject.toString().startsWith("{\"xxx\":")); } @Test public void testWinkJSONObject() throws JSONException { org.apache.wink.json4j.JSONObject jsonObject = new OrderedJSONObject(); jsonObject.put("bbb", "xxx"); jsonObject.put("ccc", "xxx"); jsonObject.put("aaa", "xxx"); jsonObject.put("xxx", "xxx"); assertEquals("{\"bbb\":\"xxx\",\"ccc\":\"xxx\",\"aaa\":\"xxx\",\"xxx\":\"xxx\"}", jsonObject.toString()); }
источник