Please wait. This can take some minutes ...
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.
org.milyn.util.MultiLineToStringBuilder Maven / Gradle / Ivy
package org.milyn.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.milyn.container.ExecutionContext;
import org.milyn.payload.FilterResult;
import org.milyn.payload.FilterSource;
/**
* Static utility class for generating JSON like multi line Strings
* from Maps, List, Arrays and the ExecutionContext.
*
* These methods do traverse sub Maps/Collections/Arrays. They can handle references
* to parent nodes or to them selfs.
*
* @author maurice_zeijen
*
*/
public class MultiLineToStringBuilder {
private static final int SPACES = 3;
private static final String PARENT_OPEN = "PARENT-";
private static final String PARENT_CLOSE = "";
private static final String SPACE = " ";
private static final String QUOTE = "\"";
private static final String SQUARE_BRACKET_CLOSE = "]";
private static final String SQUARE_BRACKET_OPEN = "[";
private static final String THIS = "THIS";
private static final String NULL = "NULL";
private static final String VALUE_KEY_SEPARATOR = " : ";
private static final String COMMA = ",";
private static final String CURLY_BRACKET_CLOSE = "}";
private static final String CURLY_BRACKET_OPEN = "{";
private static final String NL = System.getProperty("line.separator");
private static final Pattern NL_PATTERN = Pattern.compile("\r\n|\n|\r");
private static final List EXECUTION_CONTEXT_FILTER_LIST = new ArrayList();
static {
//These keys are exluded for the execution context string
EXECUTION_CONTEXT_FILTER_LIST.add(FilterResult.CONTEXT_KEY);
EXECUTION_CONTEXT_FILTER_LIST.add(FilterSource.CONTEXT_KEY);
}
private MultiLineToStringBuilder() {
}
/**
* Creates a multi line JSON like string for the execution context
*
* @param executionContext The ExecutionContext
* @return The String representation
*/
public static String toString(ExecutionContext executionContext) {
Stack stack = new Stack();
stack.push(executionContext);
StringBuilder builder = new StringBuilder();
builder.append("BeanContext : ");
builder.append(toString(executionContext.getBeanContext().getBeanMap(), stack, new ArrayList()));
builder.append(NL);
builder.append(NL);
builder.append("Attributes : ");
builder.append(toString(executionContext.getAttributes(), stack, EXECUTION_CONTEXT_FILTER_LIST));
return builder.toString();
}
/**
* Creates a multi line JSON like string representation from a Map
*
* @param map The Map to create the string from
* @return The String representation of the Map
*/
public static String toString(Map extends Object, ? extends Object> map) {
return toString(map, Collections.emptyList());
}
/**
* Creates a multi line JSON like string representation from a Map
*
* @param map The Map to create the string from
* @param filterKeyList A list of objects that are ignored when encountered as keys
* @return The String representation of the Map
*/
public static String toString(Map extends Object, ? extends Object> map, List> filterKeyList) {
Stack stack = new Stack();
stack.add(new Object()); // A little hack to make sure that the first level is rendered correctly
return toString(map, stack, filterKeyList);
}
/**
* Creates a multi line JSON like string representation from a Collection.
*
* @param map The Map to create the string from
* @return The String representation of the Map
*/
public static String toString(Collection extends Object> collection) {
return toString(collection, Collections.emptyList());
}
/**
* Creates a multi line JSON like string representation from a Collection
*
* @param map The Map to create the string from
* @param filterKeyList A list of objects that are ignored when encountered as keys
* @return The String representation of the Map
*/
public static String toString(Collection extends Object> collection, List> filterKeyList) {
Stack stack = new Stack();
stack.add(new Object()); // A little hack to make sure that the first level is rendered correctly
return toString(collection, stack, filterKeyList);
}
/**
* Creates a multi line JSON like string representation from an Array
*
* @param map The Map to create the string from
* @return The String representation of the Map
*/
public static String toString(Object[] array) {
return toString(array, Collections.emptyList());
}
/**
* Creates a multi line JSON like string representation from an Array
*
* @param map The Map to create the string from
* @param filterKeyList A list of objects that are ignored when encountered as keys
* @return The String representation of the Map
*/
public static String toString(Object[] array, List> filterKeyList) {
Stack stack = new Stack();
stack.add(new Object()); // A little hack to make sure that the first level is renderd ok
return toString(array, stack, filterKeyList);
}
/**
* Creates a multi line JSON like string representation from a Map
*
* @param map The Map to create the string from
* @param filterKeyList A list of objects that are ignored when encountered as keys
* @return The String representation of the Map
*/
private static String toString(Map extends Object, ? extends Object> map, Stack parentStack, List> filterKeys) {
StringBuilder builder = new StringBuilder();
builder.append(CURLY_BRACKET_OPEN);
String indent = StringUtils.repeat(SPACE, parentStack.size()*SPACES);
String bracketIndent = StringUtils.repeat(SPACE, (parentStack.size()-1)*SPACES);
int i = 0;
int size = map.entrySet().size();
for(Entry extends Object, ? extends Object> entry : map.entrySet()) {
String key = entry.getKey().toString();
if(filterKeys.contains(key)) {
continue;
}
builder.append(NL);
Object value = entry.getValue();
builder.append(indent);
builder.append(QUOTE);
builder.append(key);
builder.append(QUOTE);
builder.append(VALUE_KEY_SEPARATOR);
if(value == null) {
builder.append(NULL);
} else {
if(isTraversable(value) && parentStack.contains(value)) {
processParent(parentStack, builder, value);
} else if(value == map){
builder.append(THIS);
} else {
processValue(map, value, key, parentStack, builder, filterKeys);
}
}
i++;
if(i < size) {
builder.append(COMMA);
}
}
if(i > 0) {
builder.append(NL);
builder.append(bracketIndent);
}
builder.append(CURLY_BRACKET_CLOSE);
return builder.toString();
}
private static String toString(Collection extends Object> collection, Stack parentStack, List> filterKeys) {
StringBuilder builder = new StringBuilder();
builder.append(SQUARE_BRACKET_OPEN);
String indent = StringUtils.repeat(SPACE, parentStack.size()*SPACES);
String bracketIndent = StringUtils.repeat(SPACE, (parentStack.size()-1)*SPACES);
int i = 0;
int size = collection.size();
for(Object value : collection) {
builder.append(NL);
builder.append(indent);
if(value == null) {
builder.append(NULL);
} else {
if(isTraversable(value) && parentStack.contains(value)) {
processParent(parentStack, builder, value);
} else if(value == collection){
builder.append(THIS);
} else {
processValue(collection, value, null, parentStack, builder, filterKeys);
}
}
i++;
if(i < size) {
builder.append(COMMA);
}
}
if(i > 0) {
builder.append(NL);
builder.append(bracketIndent);
}
builder.append(SQUARE_BRACKET_CLOSE);
return builder.toString();
}
private static String toString(Object[] array, Stack parentStack, List> filterKeys) {
StringBuilder builder = new StringBuilder();
builder.append(SQUARE_BRACKET_OPEN);
String indent = StringUtils.repeat(SPACE, parentStack.size()*SPACES);
String bracketIndent = StringUtils.repeat(SPACE, (parentStack.size()-1)*SPACES);
int i = 0;
int size = array.length;
for(Object value : array) {
builder.append(NL);
builder.append(indent);
if(value == null) {
builder.append(NULL);
} else {
if(isTraversable(value) && parentStack.contains(value)) {
processParent(parentStack, builder, value);
} else if(value == array){
builder.append(THIS);
} else {
processValue(array, value, null, parentStack, builder, filterKeys);
}
}
i++;
if(i < size) {
builder.append(COMMA);
}
}
if(i > 0) {
builder.append(NL);
builder.append(bracketIndent);
}
builder.append(SQUARE_BRACKET_CLOSE);
return builder.toString();
}
private static void processParent(Stack parentStack, StringBuilder builder, Object value) {
int index = parentStack.indexOf(value);
builder.append(PARENT_OPEN)
.append(parentStack.size() - index)
.append(PARENT_CLOSE);
}
@SuppressWarnings("unchecked")
private static void processValue(Object current, Object value, String key, Stack parentStack, StringBuilder builder, List> filterKeys) {
if(value instanceof Map, ?>) {
parentStack.push(current);
builder.append(toString((Map extends Object, ? extends Object>) value, parentStack, filterKeys));
parentStack.pop();
} else if(value instanceof Collection>) {
parentStack.push(current);
builder.append(toString((Collection extends Object>) value, parentStack, filterKeys));
parentStack.pop();
} else if(value.getClass().isArray()) {
parentStack.push(current);
builder.append(toString((Object[]) value, parentStack, filterKeys));
parentStack.pop();
} else {
if(value instanceof Number) {
builder.append(value);
} else {
builder.append(QUOTE);
String valueStr = value.toString();
Matcher matcher = NL_PATTERN.matcher(valueStr);
if(matcher.find()) {
int keyLength = key == null ? 0 : key.length() + VALUE_KEY_SEPARATOR.length();
String spaces = StringUtils.repeat(SPACE, keyLength + (parentStack.size()*SPACES));
valueStr = matcher.replaceAll(NL + spaces);
builder.append(valueStr);
} else {
builder.append(valueStr);
}
builder.append(QUOTE);
}
}
}
private static boolean isTraversable(Object obj) {
return obj instanceof Collection> || obj instanceof Map, ?> || obj.getClass().isArray();
}
}