
org.metafacture.json.JsonEncoder Maven / Gradle / Ivy
/*
* Copyright 2013, 2014 Deutsche Nationalbibliothek
*
* 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.metafacture.json;
import java.io.IOException;
import java.io.StringWriter;
import org.metafacture.framework.FluxCommand;
import org.metafacture.framework.MetafactureException;
import org.metafacture.framework.ObjectReceiver;
import org.metafacture.framework.StreamReceiver;
import org.metafacture.framework.annotations.Description;
import org.metafacture.framework.annotations.In;
import org.metafacture.framework.annotations.Out;
import org.metafacture.framework.helpers.DefaultStreamPipe;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.io.SerializedString;
/**
* Serialises an object as JSON. Records and entities are represented
* as objects unless their name ends with []. If the name ends with [],
* an array is created.
*
* @author Christoph Böhme
* @author Michael Büchner
*
*/
@Description("Serialises an object as JSON")
@In(StreamReceiver.class)
@Out(String.class)
@FluxCommand("encode-json")
public final class JsonEncoder extends
DefaultStreamPipe> {
public static final String ARRAY_MARKER = "[]";
private final JsonGenerator jsonGenerator;
private final StringWriter writer = new StringWriter();
public JsonEncoder() {
try {
jsonGenerator = new JsonFactory().createGenerator(writer);
jsonGenerator.setRootValueSeparator(null);
} catch (final IOException e) {
throw new MetafactureException(e);
}
}
public void setPrettyPrinting(final boolean prettyPrinting) {
if (prettyPrinting) {
jsonGenerator.useDefaultPrettyPrinter();
} else {
jsonGenerator.setPrettyPrinter(null);
}
}
public boolean getPrettyPrinting() {
return jsonGenerator.getPrettyPrinter() != null;
}
/**
* By default JSON output does only have escaping where it is strictly
* necessary. This is recommended in the most cases. Nevertheless it can
* be sometimes useful to have some more escaping.
*
* @param escapeCharacters an array which defines which characters should be
* escaped and how it will be done. See
* {@link CharacterEscapes}. In most cases this should
* be null. Use like this:
* {@code int[] esc = CharacterEscapes.standardAsciiEscapesForJSON();
* // and force escaping of a few others:
* esc['\''] = CharacterEscapes.ESCAPE_STANDARD;
* JsonEncoder.useEscapeJavaScript(esc);
* }
*/
public void setJavaScriptEscapeChars(final int[] escapeCharacters) {
final CharacterEscapes ce = new CharacterEscapes() {
private static final long serialVersionUID = 1L;
@Override
public int[] getEscapeCodesForAscii() {
if (escapeCharacters == null) {
return CharacterEscapes.standardAsciiEscapesForJSON();
}
return escapeCharacters;
}
@Override
public SerializableString getEscapeSequence(final int ch) {
final String jsEscaped = escapeChar((char) ch);
return new SerializedString(jsEscaped);
}
};
jsonGenerator.setCharacterEscapes(ce);
}
@Override
public void startRecord(final String id) {
final StringBuffer buffer = writer.getBuffer();
buffer.delete(0, buffer.length());
startGroup(id);
}
@Override
public void endRecord() {
endGroup();
try {
jsonGenerator.flush();
} catch (final IOException e) {
throw new MetafactureException(e);
}
getReceiver().process(writer.toString());
}
@Override
public void startEntity(final String name) {
startGroup(name);
}
@Override
public void endEntity() {
endGroup();
}
@Override
public void literal(final String name, final String value) {
try {
final JsonStreamContext ctx = jsonGenerator.getOutputContext();
if (ctx.inObject()) {
jsonGenerator.writeFieldName(name);
}
if (value == null) {
jsonGenerator.writeNull();
} else {
jsonGenerator.writeString(value);
}
} catch (final JsonGenerationException e) {
throw new MetafactureException(e);
}
catch (final IOException e) {
throw new MetafactureException(e);
}
}
private void startGroup(final String name) {
try {
final JsonStreamContext ctx = jsonGenerator.getOutputContext();
if (name.endsWith(ARRAY_MARKER)) {
if (ctx.inObject()) {
jsonGenerator.writeFieldName(name.substring(0, name.length() - ARRAY_MARKER.length()));
}
jsonGenerator.writeStartArray();
} else {
if (ctx.inObject()) {
jsonGenerator.writeFieldName(name);
}
jsonGenerator.writeStartObject();
}
} catch (final JsonGenerationException e) {
throw new MetafactureException(e);
}
catch (final IOException e) {
throw new MetafactureException(e);
}
}
private void endGroup() {
try {
final JsonStreamContext ctx = jsonGenerator.getOutputContext();
if (ctx.inObject()) {
jsonGenerator.writeEndObject();
} else if (ctx.inArray()) {
jsonGenerator.writeEndArray();
}
} catch (final JsonGenerationException e) {
throw new MetafactureException(e);
}
catch (final IOException e) {
throw new MetafactureException(e);
}
}
private String escapeChar(char ch) {
final String namedEscape = namedEscape(ch);
if (namedEscape != null) {
return namedEscape;
}
if (ch < 0x20 || 0x7f < ch ) {
return unicodeEscape(ch);
}
return Character.toString(ch);
}
private String namedEscape(char ch) {
switch(ch) {
case '\b': return "\\b";
case '\n': return "\\n";
case '\t': return "\\t";
case '\f': return "\\f";
case '\r': return "\\r";
case '\'': return "\\'";
case '\\': return "\\\\";
case '"': return "\\\"";
case '/': return "\\/";
default:
return null;
}
}
private String unicodeEscape(char ch) {
return String.format("\\u%4H", ch).replace(' ', '0');
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy