/** * == @Spearal ==> * * Copyright (C) 2014 Franck WOLFF & William DRAI (http://www.spearal.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 org.spearal.impl; import java.io.IOException; import java.io.PrintStream; import org.spearal.SpearalPrinter; /** * @author Franck WOLFF */ @SuppressWarnings("boxing") public class SpearalPrinterImpl implements SpearalPrinter { protected final PrintStream out; protected final int maxStringLength; protected final int maxByteArrayLength; protected int indent; public SpearalPrinterImpl(PrintStream out) { this(out, 256, 256); } public SpearalPrinterImpl(PrintStream out, int maxStringLength, int maxByteArrayLength) { if (out == null) throw new NullPointerException(); this.out = out; this.maxStringLength = maxStringLength; this.maxByteArrayLength = maxByteArrayLength; this.indent = 0; } public PrintStream getOut() { return out; } public int getMaxStringLength() { return maxStringLength; } public int getMaxByteArrayLength() { return maxByteArrayLength; } @Override public void printNull() throws IOException { out.print("null"); } @Override public void printBoolean(boolean value) throws IOException { out.print(value); } @Override public void printDateTime(SpearalDateTime value) throws IOException { out.print(value); } @Override public void printIntegral(long value) throws IOException { out.print(value); } @Override public void printBigIntegral(StringData value) throws IOException { out.print(value.value); } @Override public void printFloating(double value) throws IOException { out.print(value); } @Override public void printBigFloating(StringData value) throws IOException { out.print(value.value); } @Override public void printString(StringData value) throws IOException { out.printf("\"%s\"", escape(value.value)); } @Override public void printByteArray(byte[] value, int index, boolean reference) throws IOException { if (reference) out.printf("(^%d)", index); else { out.printf("<#%d> [", index); for (int i = 0; i < value.length; i++) { if (i > 0) out.print(", "); out.printf("0x%02x", value[i] & 0xff); if (i >= maxByteArrayLength) { out.printf(" (and %d more...)", value.length - i); break; } } out.print(']'); } } @Override public void printCollectionStart(int index, int length) throws IOException { out.printf("<#%d> [", index); indent++; } @Override public void printCollectionItemStart(int index, int itemIndex) throws IOException { if (index != 0) out.print(','); indent(); } @Override public void printCollectionItemEnd(int index, int itemIndex) throws IOException { } @Override public void printCollectionEnd(int index) throws IOException { indent--; indent(); out.print(']'); } @Override public void printCollectionReference(int index) throws IOException { out.printf("(^%d)", index); } @Override public void printMapStart(int index, int length) throws IOException { out.printf("<#%d> {", index); indent++; } @Override public void printMapKeyStart(int index, int entryIndex) throws IOException { if (index != 0) out.print(','); indent(); } @Override public void printMapKeyEnd(int index, int entryIndex) throws IOException { out.print(" -> "); } @Override public void printMapValueStart(int index, int entryIndex) throws IOException { indent++; } @Override public void printMapValueEnd(int index, int entryIndex) throws IOException { indent--; } @Override public void printMapEnd(int index) throws IOException { indent--; indent(); out.print('}'); } @Override public void printMapReference(int index) throws IOException { out.printf("(^%d)", index); } @Override public void printEnum(StringData className, StringData value) throws IOException { out.printf("%s.%s", className.value, value.value); } @Override public void printClass(StringData className) throws IOException { out.print(className.value); } @Override public void printBeanStart(int index, StringData classDescription, String[] classNames) throws IOException { boolean first = true; for (String className : classNames) { if (first) first = false; else out.print(", "); out.print(className); } out.printf(" <#%d> {", index); indent++; } @Override public void printBeanPropertyStart(int index, String propertyName, int propertyIndex) { if (propertyIndex > 0) out.print(','); indent(); out.printf("%s: ", propertyName); } @Override public void printBeanPropertyEnd(int index, int propertyIndex) { } @Override public void printBeanEnd(int index) throws IOException { indent--; indent(); out.print('}'); } @Override public void printBeanReference(int index) throws IOException { out.printf("(^%d)", index); } protected void indent() { out.println(); for (int i = 0; i < indent; i++) out.print(" "); } protected String escape(String s) { if (s == null || s.length() == 0) return s; StringBuilder sb = new StringBuilder(Math.min(s.length(), maxStringLength)); final int max = s.length(); for (int i = 0; i < max; i++) { char c = s.charAt(i); escape(c, sb); if (i >= maxStringLength) { sb.append(" (and "); sb.append(s.length() - 1); sb.append(" more...)"); break; } } return sb.toString(); } protected void escape(char c, StringBuilder sb) { if (c >= 0x20 && c <= 0x7F) { if (c == '"' || c == '\\') sb.append('\\'); sb.append(c); } else { switch (c) { case '\b': sb.append("\\b"); break; case '\t': sb.append("\\t"); break; case '\n': sb.append("\\n"); break; case '\f': sb.append("\\f"); break; case '\r': sb.append("\\r"); break; default: { String hex = Integer.toHexString(c); switch (hex.length()) { case 1: sb.append("\\u000"); break; case 2: sb.append("\\u00"); break; case 3: sb.append("\\u0"); break; default: sb.append("\\u"); break; } sb.append(hex); break; } } } } }