• Stars
    star
    488
  • Rank 90,182 (Top 2 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Java utility is designed to FLATTEN nested JSON objects and even more to UNFLATTEN them back

Maven Central codecov

json-flattener

A Java utility is designed to FLATTEN nested JSON objects and even more to UNFLATTEN them back.

Purpose

Converts a nested JSON

{ "a":
  { "b": 1,
    "c": null,
    "d": [false, true]
  },
  "e": "f",
  "g": 2.3
}

into a flattened JSON

{ "a.b": 1,
  "a.c": null,
  "a.d[0]": false,
  "a.d[1]": true,
  "e": "f",
  "g": 2.3
}

or a Java Map

// {a.b=1, a.c=null, a.d[0]=false, a.d[1]=true, e=f, g=2.3}

Maven Repo

<dependency>
	<groupId>com.github.wnameless.json</groupId>
	<artifactId>json-flattener</artifactId>
	<version>${newestVersion}</version>
	<!-- Newest version shows in the maven-central badge above -->
</dependency>

Quick Start

String json = "{ \"a\" : { \"b\" : 1, \"c\": null, \"d\": [false, true] }, \"e\": \"f\", \"g\":2.3 }";

// { "a":
//   { "b": 1,
//     "c": null,
//     "d": [false, true]
//   },
//   "e": "f",
//   "g": 2.3
// }

Flatten to Java Map

Map<String, Object> flattenJson = JsonFlattener.flattenAsMap(json);

System.out.println(flattenJson);
// {a.b=1, a.c=null, a.d[0]=false, a.d[1]=true, e=f, g=2.3}

Flatten to JSON string

String jsonStr = JsonFlattener.flatten(json);

System.out.println(jsonStr);
// {"a.b":1,"a.c":null,"a.d[0]":false,"a.d[1]":true,"e":"f","g":2.3}

Unflatten from JSON string

String nestedJson = JsonUnflattener.unflatten(jsonStr);

System.out.println(nestedJson);
// {"a":{"b":1,"c":null,"d":[false,true]},"e":"f","g":2.3}

Flatten or Unflatten with reserved characters

// Supports JSON keys which contain dots or square brackets
String flattendJsonWithDotKey = JsonFlattener.flatten("[{\"a.a.[\":1},2,{\"c\":[3,4]}]");

System.out.println(flattendJsonWithDotKey);
// {"[0][\"a.a.[\"]":1,"[1]":2,"[2].c[0]":3,"[2].c[1]":4}

String nestedJsonWithDotKey = JsonUnflattener.unflatten(
        "{\"[1][0]\":2,\"[0]\":1,\"[1][1]\":3,\"[2]\":4,\"[3][\\\"ab.c.[\\\"]\":5}");
	
System.out.println(nestedJsonWithDotKey);
// [1,[2,3],4,{"ab.c.[":5}]

Feature List

Name Description Since
Jackson, Gson, org.json, Jakarta Upgrading json-base to support 4 major JSON implementations v0.16.0
JsonFlattenerFactory produces any JsonFlattener with preconfigured settings v0.14.0
JsonUnflattenerFactory produces any JsonUnflattener with preconfigured settings v0.14.0
IgnoreReservedCharacters reserved characters in keys can be ignored v0.13.0
JsonCore customized JSON libarary(Jackson, GSON, etc.) supported v0.12.0
JsonUnflattener.unflatten(Map) new API for Java Map unflattening v0.11.0
JsonUnflattener.unflattenAsMap new API for JSON unflattening v0.11.0
JsonFlattener.flattenAsMap(JsonValueBase) new API for JSON flattening v0.8.1
FlattenMode.KEEP_PRIMITIVE_ARRAYS new FlattenMode to keep all primitive JSON arrrays v0.8.0
JsonValueBase comes from json-base lib, is introduced to improve performance v0.7.0
StringEscapePolicy ALL, ALL_BUT_SLASH, ALL_BUT_UNICODE, ALL_BUT_SLASH_AND_UNICODE, DEFAULT v0.6.0
CharSequenceTranslatorFactory customized StringEscapePolicy v0.5.0
FlattenMode.MONGODB dot notation v0.4.0
KeyTransformer manipulates keys before flattening v0.4.0
LeftAndRightBrackets customized brackets v0.3.0
Reader input JSON as Java Reader v0.3.0
FlattenMode NORMAL, KEEP_ARRAYS v0.2.0
StringEscapePolicy NORMAL, ALL_UNICODES v0.2.0
Separator customized separator v0.2.0
PrintMode MINIMAL, PRETTY v0.2.0

🔝 JsonFlattenerFactory - produces any JsonFlattener with preconfigured settings

// Inside Spring configuration class
@Bean
public JsonFlattenerFactory jsonFlattenerFactory() {
  // Changes the default PrintMode from MINIMAL to PRETTY
  Consumer<JsonFlattener> configurer = jf -> jf.withPrintMode(PrintMode.PRETTY);
  // Alters the default JsonCore from Jackson to GSON
  JsonCore<?> jsonCore = new GsonJsonCore();

  return new JsonFlattenerFactory(configurer, jsonCore);
}

// In any other Spring environment class
@Autowired
JsonFlattenerFactory jsonFlattenerFactory;

public void usageExamples(String json) {
  JsonFlattener jf1 = jsonFlattenerFactory.build(json);
  JsonFlattener jf2 = jsonFlattenerFactory.build(new StringReader(json));
  JsonFlattener jf3 = jsonFlattenerFactory.build(new GsonJsonCore().parse(json));
}

🔝 JsonUnflattenerFactory - produces any JsonUnflattener with preconfigured settings

// Inside Spring configuration class
@Bean
public JsonUnflattenerFactory jsonUnflattenerFactory() {
  // Sets the FlattenMode to MONGODB
  Consumer<JsonUnflattener> configurer = ju -> ju.withFlattenMode(FlattenMode.MONGODB);
  // Alters the default JsonCore from Jackson to GSON
  JsonCore<?> jsonCore = new GsonJsonCore();

  return new JsonUnflattenerFactory(configurer, jsonCore);
}

// In any other Spring environment class
@Autowired
JsonUnflattenerFactory jsonUnflattenerFactory;

public void usageExamples(String json) {
  JsonUnflattener ju1 = jsonUnflattenerFactory.build(json);
  JsonUnflattener ju2 = jsonUnflattenerFactory.build(new StringReader(json));
  JsonUnflattener ju3 = jsonUnflattenerFactory.build((Map<String, ?>) new ObjectMapper().readValue(json, Map.class));
}

🔝 IgnoreReservedCharacters - reserved characters in keys can be ignored

String json = "{\"matrix\":{\"agent.smith\":\"1999\"}}";

System.out.println(JsonFlattener.flatten(json));
// {"matrix[\"agent.smith\"]":"1999"}

System.out.println(new JsonFlattener(json).ignoreReservedCharacters().flatten());
// {"matrix.agent.smith":"1999"}
// The escape of reserved character('.') has been ignored

new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB).flatten();
// Throws IllegalArgumentException

System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB).ignoreReservedCharacters().flatten());
// {"matrix.agent.smith":"1999"}
// The check of reserved character('.') has been ignored

🔝 JsonCore - customized JSON libarary supported

JsonFlattener jf;
JsonUnflattener ju;

ObjectMapper mapper = new ObjectMapper() {
  {
    configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
    configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, true);
  }
};
jf = new JsonFlattener(new JacksonJsonCore(mapper), json);
ju = new JsonUnflattener(new JacksonJsonCore(mapper), json);

Gson gson = new GsonBuilder().serializeNulls().create();
jf = new JsonFlattener(new GsonJsonCore(gson), json);
ju = new JsonUnflattener(new GsonJsonCore(gson), json);

🔝 JsonUnflattener.unflatten(Map) - new API for Java Map unflattening

String json = "{\"abc\":{\"def\":[1,2,{\"g\":{\"h\":[3]}}]}}";
Map<String, Object> flattenedMap = JsonFlattener.flattenAsMap(json);

String unflattenedJson = JsonUnflattener.unflatten(flattenedMap);

🔝 JsonUnflattener.unflattenAsMap - new API for JSON unflattening

String json = "{\"abc\":{\"def\":[1,2,{\"g\":{\"h\":[3]}}]}}";
String flattenedJson = JsonFlattener.flatten(json);
Map<String, Object> flattenedMap = JsonFlattener.flattenAsMap(json);

Map<String, Object> unflattenedMap;
unflattenedMap = JsonUnflattener.unflattenAsMap(flattenedJson);
unflattenedMap = JsonUnflattener.unflattenAsMap(flattenedMap);

🔝 JsonFlattener.flattenAsMap(JsonValueBase) - new API for JSON flattening

JsonValueBase<?> jsonVal;

// JacksonJsonValue, which is provided by json-base lib, can wrap Jackson jsonNode to JsonValueBase
jsonVal = new JacksonJsonValue(jsonNode);

Map<String, Object> flattenMap = JsonFlattener.flattenAsMap(jsonVal);

🔝 FlattenMode.KEEP_PRIMITIVE_ARRAYS - new FlattenMode to keep all primitive JSON arrrays

String json = "{\"ary\":[true,[1, 2, 3],false]}";
System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.KEEP_PRIMITIVE_ARRAYS).flatten());
// {"ary[0]":true,"ary[1]":[1,2,3],"ary[2]":false}

This mode only keeps arrays which contain only primitive types(strings, numbers, booleans, and null).

🔝 JsonValueBase - comes from json-base lib, is introduced to improve performance

JsonValueBase<?> jsonVal;

// GsonJsonValue, which is provided by json-base lib, can wrap Gson jsonElement to JsonValueBase
jsonVal = new GsonJsonValue(jsonElement);

// JacksonJsonValue, which is provided by json-base lib, can wrap Jackson jsonNode to JsonValueBase
jsonVal = new JacksonJsonValue(jsonNode);

// You can also implement the JsonValueBase interface for any JSON lib you are using
jsonVal = new CostumeJsonValue(yourJsonVal);

new JsonFlattener(jsonVal);

🔝 StringEscapePolicy - ALL, ALL_BUT_SLASH, ALL_BUT_UNICODE, ALL_BUT_SLASH_AND_UNICODE, DEFAULT

StringEscapePolicy.ALL //                       Escapes all JSON special characters and Unicode
StringEscapePolicy.ALL_BUT_SLASH //             Escapes all JSON special characters and Unicode but slash('/')
StringEscapePolicy.ALL_BUT_UNICODE //           Escapes all JSON special characters but Unicode
StringEscapePolicy.ALL_BUT_SLASH_AND_UNICODE // Escapes all JSON special characters but slash('/') and Unicode
StringEscapePolicy.DEFAULT //                   Escapes all JSON special characters but slash('/') and Unicode

🔝 CharSequenceTranslatorFactory - customized StringEscapePolicy

public class MyStringEscapePolicy implements CharSequenceTranslatorFactory { ... }

StringEscapePolicy can be customized by implementing the CharSequenceTranslatorFactory interface.

For example, if you don't want the slash(/) and backslash(\) to be escaped:

new JsonFlattener(YOUR_JSON)

        .withStringEscapePolicy(new CharSequenceTranslatorFactory() {

          @Override
          public CharSequenceTranslator getCharSequenceTranslator() {
            return new AggregateTranslator(
                new LookupTranslator(new HashMap<CharSequence, CharSequence>() {
                  private static final long serialVersionUID = 1L;
                  {
                    put("\"", "\\\"");
                    // put("\\", "\\\\");
                    // put("/", "\\/"); 
                  }
                }), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE));
          }

        });

🔝 FlattenMode.MONGODB - dot notation

String json = "{\"abc\":{\"def\":[123]}}";
System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB).flatten());
// {"abc.def.0":123}

json = "{\"abc.def.0\":123}";
System.out.println(new JsonUnflattener(json).withFlattenMode(FlattenMode.MONGODB).unflatten());
// {"abc":{"def":[123]}}

// With FlattenMode.MONGODB, separator can still be changed
json = "{\"abc\":{\"def\":[123]}}";
System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB).withSeparator('*').flatten());
// {"abc*def*0":123}

json = "{\"abc*def*0\":123}";
System.out.println(new JsonUnflattener(json).withFlattenMode(FlattenMode.MONGODB).withSeparator('*').unflatten());
// {"abc":{"def":[123]}}

🔝 KeyTransformer - manipulates keys before flattening

String json = "{\"abc\":{\"de.f\":123}}";
JsonFlattener jf = new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB);

// This will throw an exception because FlattenMode.MONGODB won't support separator(.) in the key
jf.flatten();

// KeyTransformer can be used to manipulate keys before flattening 
KeyTransformer kt = new KeyTransformer() {
  @Override
  public String transform(String key) {
    return key.replace('.', '_');
  }
};
jf.withKeyTransformer(kt);
System.out.println(jf.flatten());
// {"abc.de_f":123}

// KeyTransformer should be set in JsonUnflattener as well
json = "{\"abc.de_f\":123}";
kt = new KeyTransformer() {
  @Override
  public String transform(String key) {
    return key.replace('_', '.');
  }
};
JsonUnflattener ju = new JsonFlattener(json).withFlattenMode(FlattenMode.MONGODB).withKeyTransformer(kt);
System.out.println(ju.unflatten());
// {"abc":{"de.f":123}}

🔝 LeftAndRightBrackets - customized brackets

// JsonFlattener - Brackets can be changed from square brackets([]) to any 2 arbitrary characters
String json = "{\"abc\":{\"def\":[123]}}";
System.out.println(new JsonFlattener(json).withLeftAndRightBrackets('(', ')').flatten());
// {"abc.def(0)":123}

// JsonUnflattener - if special brackets are using, it should be set into the unflattener as well
json = "{"abc.def(0)":123}";
System.out.println(new JsonUnflattener(json).withLeftAndRightBrackets('(', ')').unflatten());
// {"abc":{"def":[123]}}

🔝 Reader - input JSON as Java Reader

InputStream inputStream = new FileInputStream("simple.json");
Reader reader = new InputStreamReader(inputStream);

// Support Reader as input 
JsonFlattener jf = new JsonFlattener(reader);
JsonUnflattener ju = new JsonUnflattener(reader);

🔝 FlattenMode - NORMAL, KEEP_ARRAYS

String json = "{\"abc\":{\"def\":[1,2,{\"g\":{\"h\":[3]}}]}}";

// FlattenMode.NORMAL(default) - flatten everything
System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.NORMAL).flatten());
// {"abc.def[0]":1,"abc.def[1]":2,"abc.def[2].g.h[0]":3}

// FlattenMode.KEEP_ARRAYS - flatten all except arrays
System.out.println(new JsonFlattener(json).withFlattenMode(FlattenMode.KEEP_ARRAYS).flatten());
// {"abc.def":[1,2,{"g.h":[3]}]}

// When the flattened outcome can NOT suit in a Java Map, it will still be put in the Map with "root" as its key. 
Map<String, Object> map = new JsonFlattener("[[123]]").withFlattenMode(FlattenMode.KEEP_ARRAYS).flattenAsMap();
System.out.println(map.get("root"));
// [[123]]

🔝 StringEscapePolicy - NORMAL, ALL_UNICODES

String json = "{\"abc\":{\"def\":\"太極\\t\"}}";

// StringEscapePolicy.NORMAL(default) - escape only speacial characters
System.out.println(new JsonFlattener(json).withStringEscapePolicy(StringEscapePolicy.NORMAL).flatten());
// {"abc.def":"太極\t"}

// StringEscapePolicy.ALL_UNICODES - escape speacial characters and unicodes
System.out.println(new JsonFlattener(json).withStringEscapePolicy(StringEscapePolicy.ALL_UNICODES).flatten());
// {"abc.def":"\u592A\u6975\t"}

🔝 Separator - customized separator

// JsonFlattener - separator can be changed from dot(.) to an arbitrary character
String json = "{\"abc\":{\"def\":123}}";
System.out.println(new JsonFlattener(json).withSeparator('*').flatten());
// {"abc*def":123}

// JsonUnflattener - if a special separator is using, it should be set into the unflattener as well
json = "{\"abc*def\":123}";
System.out.println(new JsonUnflattener(json).withSeparator('*').unflatten());
// {"abc":{"def":123}}

🔝 PrintMode - MINIMAL, PRETTY

String json = "{\"abc\":{\"def\":123}}";

// JsonFlattener
// PrintMode.MINIMAL(default)
System.out.println(new JsonFlattener(json).withPrintMode(PrintMode.MINIMAL).flatten());
// {"abc.def":123}

// PrintMode.PRETTY
System.out.println(new JsonFlattener(json).withPrintMode(PrintMode.PRETTY).flatten());
// {
//   "abc.def": 123
// }

// JsonUnflattener
// PrintMode.MINIMAL(default)
json = "{\"abc.def\":123}";
System.out.println(new JsonUnflattener(json).withPrintMode(PrintMode.MINIMAL).unflatten());
// {"abc":{"def":123}}

// PrintMode.PRETTY
System.out.println(new JsonUnflattener(json).withPrintMode(PrintMode.PRETTY).unflatten());
// {
//   "abc": {
//     "def": 123
//   }
// }

MISC

Note Since
Java 8 required. v0.5.0
StringEscapePolicy.DEFAULT, which escapes all special characters but slash('/') and Unicode, becomes the default setting. v0.6.0
Group ID is changed from [com.github.wnameless] to [com.github.wnameless.json]. v0.7.0
Java Module supported. v0.9.0
The Map produced by JsonFlattener#flattenAsMap after serialization is now identical to the JSON produced by JsonFlattener#flatten. Before v0.10.0, the serialized flattened Map may be different at some edge cases(ex: input keys contain separator('.')). v0.10.0

More Repositories

1

docker-oracle-xe-11g

Dockerfile of Oracle Database Express Edition 11g Release 2
Shell
1,311
star
2

spring-bulk-api

Add bulk operations support to any Spring RESTful API by a single annotation @EnableBulkApi.
Java
25
star
3

rare_map

Translate legacy db to ActiveRecord models
Ruby
23
star
4

docker-mysql_phpmyadmin

MySQL + phpMyAdmin
Shell
17
star
5

smartcard-reader

A smartcard reader util for Java
Java
17
star
6

docker-cas_mysql

CAS single sign-on server + MySQL
Shell
13
star
7

plus_codes-ruby

Ruby implementation of Google Open Location Code(Plus+Codes)
Ruby
7
star
8

rubycollect4j

Ruby Collections for Java
Java
6
star
9

nullproof

A Java null arguments proofed object constructor by Guice AOP or AspectJ
Java
5
star
10

json-base

A set of Java interfaces, which defines the common JSON data behaviors, can be used to decouple programming logic from JSON implementations such as Jackson, Gson, org.json and Jakarta...
Java
5
star
11

spring-security-jjwt

Integrate the Java JSON Web Token(jjwt) library into Spring Security
Java
4
star
12

spring-paper-trail

Add automatic audit trail to all stateful HTTP requests by the annotation @EnablePaperTrail
Java
4
star
13

docker-postgresql_phppgadmin

postgresql + phpPgAdmin
Shell
3
star
14

workbook-accessor

A friendly workbook reader and writer for Java based on Apache POI
Java
3
star
15

aws-price-list-api

A Java wrapper to Amazon AWS Price List (web) API
Java
2
star
16

java-testing-journey

A journey to all kinds of Java testing frameworks
Java
2
star
17

jpa-type-flattenedjson

Simulate a new datatype FlattenedJson in database based on the AttributeConverter feature of JPA 2.1 with Hibernate, QueryDsl, Jackson JSON and JsonFlattener.
Java
2
star
18

docker-openclinica

OpenClinica 3.11 for Docker
2
star
19

docker-openclinica-db

Postgres DB for OpenClinica
2
star
20

thymeleaf-dropdown-dialect

A Bootstrap dropdown dialect for Thymeleaf
Java
1
star
21

spring-boot-up-apt

Annotation Processing Tool(s) of SpringBootUp
Java
1
star
22

json-bean-populator

Populate Java beans by annotations and given JSON data
Java
1
star
23

basic-guava-example

Java
1
star
24

basic-mockito-example

Java
1
star
25

spring-boot-up-data-mongodb

MongoDB enhancement brought by SpringBootUp
Java
1
star
26

spring-react-jsonschema-form

Integrate the famous react-jsonschema-form js library into Spring Framework
JavaScript
1
star
27

sheet2hash

Convert Excel or Spreadsheet to Ruby hash
Ruby
1
star
28

spring-routing-resolver

An easy way to find out all routing paths in Spring annotated controllers.
Java
1
star