Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2019, Continual.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.continual.util.data.json;
import java.io.InputStream;
import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import io.continual.util.data.json.JsonVisitor.ArrayOfObjectVisitor;
import io.continual.util.data.json.JsonVisitor.ArrayOfStringVisitor;
public class JsonUtil
{
private JsonUtil() {
}
public static JSONObject readJsonObject ( InputStream is )
{
return new JSONObject ( new CommentedJsonTokener( is ) );
}
public static JSONObject readJsonObject ( String is )
{
return new JSONObject ( new CommentedJsonTokener ( is ) );
}
public static JSONObject readJsonObject ( Reader is )
{
return new JSONObject ( new CommentedJsonTokener ( is ) );
}
public static JSONArray readJsonArray ( InputStream is )
{
return new JSONArray ( new CommentedJsonTokener ( is ) );
}
public static JSONArray readJsonArray ( String is )
{
return new JSONArray ( new CommentedJsonTokener ( is ) );
}
public static JSONArray readJsonArray ( Reader is )
{
return new JSONArray ( new CommentedJsonTokener ( is ) );
}
public static Object readJsonValue ( String is )
{
return new CommentedJsonTokener ( is ).nextValue ();
}
public static JSONObject clone ( JSONObject that )
{
if ( that == null ) return null;
return (JSONObject) cloneJsonValue ( that );
}
public static JSONArray clone ( JSONArray that )
{
if ( that == null ) return null;
return (JSONArray) cloneJsonValue ( that );
}
public static Object cloneJsonValue ( Object value )
{
if ( value == null ) return null;
if ( value instanceof JSONObject )
{
final JSONObject result = new JSONObject ();
final JSONObject obj = (JSONObject) value;
for ( Object key : obj.keySet () )
{
final String keyStr = key.toString ();
result.put ( keyStr, cloneJsonValue ( obj.get ( keyStr ) ) );
}
return result;
}
else if ( value instanceof JSONArray )
{
final JSONArray array = (JSONArray) value;
final JSONArray result = new JSONArray ();
for ( int i=0; i -1 )
{
a.remove ( found );
return true;
}
return false;
}
public static void writeDate ( JSONObject base, String key, Date d ) throws JSONException
{
final ZonedDateTime zdt = d.toInstant ().atZone ( kLocalZone );
base.put ( key, zdt.format ( DateTimeFormatter.ISO_LOCAL_DATE ) );
}
public static void writeDateTime ( JSONObject base, String key, Date d ) throws JSONException
{
base.put ( key, writeDate ( d ) );
}
public static String writeDate ( Date d ) throws JSONException
{
final ZonedDateTime zdt = d.toInstant ().atZone ( kLocalZone );
return zdt.format ( DateTimeFormatter.ISO_LOCAL_DATE );
}
public static String writeDate ( LocalDate d ) throws JSONException
{
return d.format ( DateTimeFormatter.ISO_LOCAL_DATE );
}
public static LocalDate readDate ( JSONObject base, String key ) throws JSONException
{
final Object o = base.opt ( key );
if ( o == null ) return null;
if ( o instanceof Long )
{
final Instant i = Instant.ofEpochMilli ( (Long)o );
return i.atZone ( kLocalZone ).toLocalDate ();
}
if ( o instanceof String )
{
// try basic ISO types
try
{
final LocalDateTime ldt = LocalDateTime.parse ( (String)o );
return ldt.toLocalDate ();
}
catch ( DateTimeParseException x )
{
// no good; ignore
}
try
{
return LocalDate.parse ( (String)o );
}
catch ( DateTimeParseException x )
{
// no good; ignore
}
// then other formats
for ( String format : dateFormats )
{
try
{
final SimpleDateFormat sdf = new SimpleDateFormat ( format );
final Date d = sdf.parse ( (String) o );
d.toInstant ().atZone ( kLocalZone ).toLocalDate ();
}
catch ( ParseException e )
{
// ignore
}
}
}
throw new JSONException ( "Unrecognized format for Date read." );
}
// EST best guess for USA
private static final ZoneId kLocalZone = ZoneId.of ( "America/New_York" );
private static String[] dateFormats =
{
"yyyy.MM.dd HH:mm:ss z",
"yyyyMMdd",
};
/**
* Load a string or array of strings into a string list.
*
* @param base the base json object
* @param key the key of the string array
* @return a list of 0 or more strings
* @throws JSONException if the key doesn't exist, or if it's not a string or array of strings
*/
public static List readStringArray ( JSONObject base, String key ) throws JSONException
{
return readStringArray ( base, key, null );
}
/**
* Parse a string value into a list.
*/
public interface StringArrayValueParser
{
Collection parse ( String rawValue );
}
/**
* Load a string or array of strings into a string list.
*
* @param base the base json object
* @param key the key of the string array
* @return a list of 0 or more strings
* @throws JSONException if the key doesn't exist, or if it's not a string or array of strings
*/
public static List readStringArray ( JSONObject base, String key, StringArrayValueParser parser ) throws JSONException
{
final LinkedList result = new LinkedList ();
final Object oo = base.opt ( key );
if ( oo == null ) throw new JSONException ( key + " does not exist" );
if ( oo instanceof JSONArray )
{
JsonVisitor.forEachStringElement ( (JSONArray)oo, new ArrayOfStringVisitor ()
{
@Override
public boolean visit ( String str ) throws JSONException
{
result.add ( str );
return true;
}
} );
}
else
{
final String val = oo.toString ();
if ( parser != null )
{
result.addAll ( parser.parse ( val ) );
}
else
{
result.add ( val );
}
}
return result;
}
/**
* Sort a JSON array of JSON objects using the value retrieved by the value expression.
* @param a an array
* @param valueExpression an expression
*/
public static void sortArrayOfObjects ( final JSONArray a, final String valueExpression )
{
sortArrayOfObjects ( a, valueExpression, false );
}
/**
* Sort a JSON array of JSON objects using the value retrieved by the value expression.
* @param a an array
* @param valueExpression an expression
* @param reverse if true, reverse the array
*/
public static void sortArrayOfObjects ( final JSONArray a, final String valueExpression, boolean reverse )
{
// build a list of objects
final LinkedList list = new LinkedList ();
JsonVisitor.forEachObjectIn ( a, new ArrayOfObjectVisitor ()
{
@Override
public boolean visit ( JSONObject t ) throws JSONException
{
if ( t != null )
{
list.add ( t );
}
return true;
}
});
// sort the list
Collections.sort ( list, new Comparator () {
@Override
public int compare ( JSONObject o1, JSONObject o2 )
{
final Object oval1 = JsonEval.eval ( o1, valueExpression );
final Object oval2 = JsonEval.eval ( o2, valueExpression );
if (( oval1 instanceof Long ) && ( oval2 instanceof Long ))
{
final Long n1 = (Long) oval1;
final Long n2 = (Long) oval2;
return n1.compareTo ( n2 );
}
if (( oval1 instanceof Integer ) && ( oval2 instanceof Integer ))
{
final Integer n1 = (Integer) oval1;
final Integer n2 = (Integer) oval2;
return n1.compareTo ( n2 );
}
final String e1 = oval1 == null ? "" : oval1.toString ();
final String e2 = oval2 == null ? "" : oval2.toString ();
return e1.compareTo ( e2 );
}
} );
if ( reverse )
{
Collections.reverse ( list );
}
// rewrite the array
int index = 0;
for ( JSONObject o : list )
{
a.put ( index++, o );
}
}
/**
* If the "local" object contains "$ref", return the referenced object, else
* return the original. If the reference is invalid (the target does not exist), return null.
* @param topLevel the top-level document
* @param local the object which may contain $ref
* @return an object or null if the reference is given but does not resolve to an object
*/
public static JSONObject resolveRef ( JSONObject topLevel, JSONObject local ) throws JSONException
{
if ( local == null ) return null;
final String ref = local.optString ( "$ref", null );
if ( ref == null ) return local;
final String[] parts = ref.split ( "/" );
if ( !parts[0].equals ( "#" ) ) throw new JSONException ( "Reference must start with #/" );
JSONObject current = topLevel;
for ( int i=1; i keys = new ArrayList<> ();
keys.addAll ( o.keySet() );
Collections.sort ( keys );
final StringBuilder sb = new StringBuilder ();
sb.append ( "{\n" );
boolean doneOne = false;
for ( String key : keys )
{
if ( doneOne )
{
sb.append ( ",\n" );
}
doneOne = true;
sb
.append ( key )
.append ( ":" )
.append ( writeConsistently ( o.get ( key ) ) );
;
}
sb.append ( "\n}\n" );
return sb.toString ();
}
/**
* Hash a json object
* @param o a json object
* @return a hash code for this object
*/
public static int hash ( JSONObject o )
{
// we have to use a predictable key order
return writeConsistently ( o ).hashCode ();
}
/**
* Write a JSON document while respecting explicit key ordering... even though such a thing makes no sense.
* @param o
* @return a JSON string
*/
public static String writeWithKeyOrder ( Object o ) { return writeWithKeyOrder ( o, 0 ); }
private static String writeWithKeyOrder ( Object o, int currentIndent )
{
if ( o instanceof JSONObject )
{
return writeWithKeyOrder ( (JSONObject) o, currentIndent );
}
else if ( o instanceof JSONArray )
{
return writeWithKeyOrder ( (JSONArray) o, currentIndent );
}
else
{
return JSONObject.valueToString ( o );
}
}
/**
* Write a JSON document while respecting explicit key ordering... even though such a thing makes no sense.
* @param a
* @return a JSON string
*/
public static String writeWithKeyOrder ( JSONArray a ) { return writeWithKeyOrder ( a, 0 ); }
private static String writeWithKeyOrder ( JSONArray a, int currentIndent )
{
final StringBuilder sb = new StringBuilder ();
sb.append ( "[\n" );
boolean doneOne = false;
for ( int i=0; i unwrittenKeys = new TreeSet<> ();
unwrittenKeys.addAll ( o.keySet () );
unwrittenKeys.remove ( skKeyOrderArray );
final ArrayList keysToWrite = new ArrayList<> ();
for ( int i=0; i remainingKeys = new ArrayList<> ();
remainingKeys.addAll ( unwrittenKeys );
Collections.sort ( remainingKeys );
keysToWrite.addAll ( remainingKeys );
// iterate the key list to write the object
final StringBuilder sb = new StringBuilder ();
sb.append ( "{\n" );
for ( int tab=0; tab