/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.usergrid.utils; import java.io.File; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.usergrid.exception.JsonReadException; import org.apache.usergrid.exception.JsonWriteException; import org.apache.usergrid.persistence.Entity; import org.apache.usergrid.persistence.index.query.Identifier; import com.fasterxml.jackson.core.io.JsonStringEncoder; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.smile.SmileFactory; import static org.apache.commons.lang.StringUtils.substringAfter; import static org.apache.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst; public class JsonUtils { private static final Logger logger = LoggerFactory.getLogger( JsonUtils.class ); static ObjectMapper mapper = new ObjectMapper(); static SmileFactory smile = new SmileFactory(); static ObjectMapper smileMapper = new ObjectMapper( smile ); private static ObjectMapper indentObjectMapper = new ObjectMapper(); private static final Pattern UUID_PATTERN = Pattern.compile( Identifier.UUID_REX ); static { //indentObjectMapper.getSerializationConfig().set( Feature.INDENT_OUTPUT, true ); indentObjectMapper.getSerializationConfig().with( SerializationFeature.INDENT_OUTPUT ); } /** Converts object to JSON string, throws runtime exception JsonWriteException on failure. */ public static String mapToJsonString( Object obj ) { try { return mapper.writeValueAsString( obj ); } catch ( Throwable t ) { if (logger.isDebugEnabled()) { logger.debug("Error generating JSON", t); } throw new JsonWriteException( "Error generating JSON", t ); } } /** Converts object to JSON string, throws runtime exception JsonWriteException on failure. */ public static String mapToFormattedJsonString( Object obj ) { try { return indentObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString( obj ); } catch ( Throwable t ) { if (logger.isDebugEnabled()) { logger.debug("Error generating JSON", t); } throw new JsonWriteException( "Error generating JSON", t ); } } /** Parses JSON string and returns object, throws runtime exception JsonReadException on failure. */ public static Object parse( String json ) { try { return mapper.readValue( json, Object.class ); } catch ( Throwable t ) { if (logger.isDebugEnabled()) { logger.debug("Error parsing JSON", t); } throw new JsonReadException( "Error parsing JSON", t ); } } public static String quoteString( String s ) { JsonStringEncoder encoder = new JsonStringEncoder(); return new String( encoder.quoteAsUTF8( s ) ); } public static ByteBuffer toByteBuffer( Object obj ) { if ( obj == null ) { return null; } byte[] bytes = null; try { bytes = smileMapper.writeValueAsBytes( obj ); } catch ( Exception e ) { logger.error( "Error getting SMILE bytes", e ); } if ( bytes != null ) { return ByteBuffer.wrap( bytes ); } return null; } public static Object fromByteBuffer( ByteBuffer byteBuffer ) { return fromByteBuffer( byteBuffer, Object.class ); } public static Object fromByteBuffer( ByteBuffer byteBuffer, Class<?> clazz ) { if ( ( byteBuffer == null ) || !byteBuffer.hasRemaining() ) { return null; } if ( clazz == null ) { clazz = Object.class; } Object obj = null; try { obj = smileMapper.readValue( byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining(), clazz ); } catch ( Exception e ) { logger.error( "Error parsing SMILE bytes", e ); } return obj; } public static JsonNode toJsonNode( Object obj ) { if ( obj == null ) { return null; } return mapper.convertValue( obj, JsonNode.class ); } @SuppressWarnings("unchecked") public static Map<String, Object> toJsonMap( Object obj ) { if ( obj == null ) { return null; } return ( Map<String, Object> ) mapper.convertValue( obj, Map.class ); } private static UUID tryConvertToUUID( Object o ) { if ( o instanceof String ) { String s = ( String ) o; if ( UUID_PATTERN.matcher( s ).matches() ) { try { return UUID.fromString( s ); } catch ( IllegalArgumentException e ) { logger.warn( "Argument to UUID.fromString({}) was invalid.", s, e ); } } } return null; } public static Object normalizeJsonTree( Object obj ) { if ( obj instanceof Map ) { @SuppressWarnings("unchecked") Map<Object, Object> m = ( Map<Object, Object> ) obj; Object o; UUID uuid; for ( Object k : m.keySet() ) { if ( k instanceof String && ( ( String ) k ).equalsIgnoreCase( "name" ) ) { continue; } o = m.get( k ); uuid = tryConvertToUUID( o ); if ( uuid != null ) { m.put( k, uuid ); } else if ( o instanceof Integer ) { m.put( k, ( ( Integer ) o ).longValue() ); } else if ( o instanceof BigInteger ) { m.put( k, ( ( BigInteger ) o ).longValue() ); } } } else if ( obj instanceof List ) { @SuppressWarnings("unchecked") List<Object> l = ( List<Object> ) obj; Object o; UUID uuid; for ( int i = 0; i < l.size(); i++ ) { o = l.get( i ); uuid = tryConvertToUUID( o ); if ( uuid != null ) { l.set( i, uuid ); } else if ( ( o instanceof Map ) || ( o instanceof List ) ) { normalizeJsonTree( o ); } else if ( o instanceof Integer ) { l.set( i, ( ( Integer ) o ).longValue() ); } else if ( o instanceof BigInteger ) { l.set( i, ( ( BigInteger ) o ).longValue() ); } } } else if ( obj instanceof String ) { UUID uuid = tryConvertToUUID( obj ); if ( uuid != null ) { return uuid; } } else if ( obj instanceof Integer ) { return ( ( Integer ) obj ).longValue(); } else if ( obj instanceof BigInteger ) { return ( ( BigInteger ) obj ).longValue(); } else if ( obj instanceof JsonNode ) { return mapper.convertValue( obj, Object.class ); } return obj; } public static Object select( Object obj, String path ) { return select( obj, path, false ); } public static Object select( Object obj, String path, boolean buildResultTree ) { if ( obj == null ) { return null; } if ( org.apache.commons.lang.StringUtils.isBlank( path ) ) { return obj; } String segment = stringOrSubstringBeforeFirst( path, '.' ); String remaining = substringAfter( path, "." ); if ( obj instanceof Map ) { Map<?, ?> map = ( Map<?, ?> ) obj; Object child = map.get( segment ); Object result = select( child, remaining, buildResultTree ); if ( result != null ) { if ( buildResultTree ) { Map<Object, Object> results = new LinkedHashMap<Object, Object>(); results.put( segment, result ); return results; } else { return result; } } return null; } if ( obj instanceof List ) { List<Object> results = new ArrayList<Object>(); List<?> list = ( List<?> ) obj; for ( Object i : list ) { Object result = select( i, path, buildResultTree ); if ( result != null ) { results.add( result ); } } if ( !results.isEmpty() ) { return results; } return null; } if ( obj instanceof Entity ) { Object child = ( ( Entity ) obj ).getProperty( segment ); Object result = select( child, remaining, buildResultTree ); if ( result != null ) { if ( buildResultTree ) { Map<Object, Object> results = new LinkedHashMap<Object, Object>(); results.put( segment, result ); return results; } else { return result; } } else { return result; } } return obj; } public static Object loadFromFilesystem( String filename ) { Object json = null; try { File file = new File( filename ); json = mapper.readValue( file, Object.class ); } catch ( Exception e ) { logger.error( "Error loading JSON", e ); } return json; } }