package com.hubspot.jackson.jaxrs; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import com.fasterxml.jackson.core.Base64Variant; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.core.filter.TokenFilter; import com.fasterxml.jackson.core.util.JsonGeneratorDelegate; /** * Clone of FilteringGeneratorDelegate that forces it to write empty objects and arrays */ public class PropertyFilteringJsonGenerator extends JsonGeneratorDelegate { private TokenFilter itemFilter; private PropertyFilteringTokenContext filterContext; public PropertyFilteringJsonGenerator(JsonGenerator generator, PropertyFilter filter) { super(generator, false); this.itemFilter = filter; this.filterContext = PropertyFilteringTokenContext.createRootContext(filter); } @Override public void writeStartArray() throws IOException { // First things first: whole-sale skipping easy if (itemFilter == null) { filterContext = filterContext.createChildArrayContext(null, false); } else { filterContext = filterContext.createChildArrayContext(itemFilter, true); delegate.writeStartArray(); } } @Override public void writeStartArray(int size) throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildArrayContext(null, false); } else { filterContext = filterContext.createChildArrayContext(itemFilter, true); delegate.writeStartArray(size); } } @Override public void writeStartArray(Object forValue) throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildArrayContext(null, false); } else { filterContext = filterContext.createChildArrayContext(itemFilter, true); delegate.writeStartArray(forValue); } } @Override public void writeStartArray(Object forValue, int size) throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildArrayContext(null, false); } else { filterContext = filterContext.createChildArrayContext(itemFilter, true); delegate.writeStartArray(forValue, size); } } @Override public void writeEndArray() throws IOException { filterContext = filterContext.closeArray(delegate); if (filterContext != null) { itemFilter = filterContext.getFilter(); } } @Override public void writeStartObject() throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildObjectContext(itemFilter, false); } else { filterContext = filterContext.createChildObjectContext(itemFilter, true); delegate.writeStartObject(); } } @Override public void writeStartObject(Object forValue) throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildObjectContext(itemFilter, false); } else { filterContext = filterContext.createChildObjectContext(itemFilter, true); delegate.writeStartObject(forValue); } } @Override public void writeStartObject(Object forValue, int size) throws IOException { if (itemFilter == null) { filterContext = filterContext.createChildObjectContext(itemFilter, false); } else { filterContext = filterContext.createChildObjectContext(itemFilter, true); delegate.writeStartObject(forValue, size); } } @Override public void writeEndObject() throws IOException { filterContext = filterContext.closeObject(delegate); if (filterContext != null) { itemFilter = filterContext.getFilter(); } } @Override public void writeFieldName(String name) throws IOException { TokenFilter state = filterContext.setFieldName(name); if (state == null) { itemFilter = null; } else if (state == TokenFilter.INCLUDE_ALL) { itemFilter = state; delegate.writeFieldName(name); } else { state = state.includeProperty(name); itemFilter = state; if (state != null) { delegate.writeFieldName(name); } } } @Override public void writeFieldName(SerializableString name) throws IOException { TokenFilter state = filterContext.setFieldName(name.getValue()); if (state == null) { itemFilter = null; } else if (state == TokenFilter.INCLUDE_ALL) { itemFilter = state; delegate.writeFieldName(name); } else { state = state.includeProperty(name.getValue()); itemFilter = state; if (state != null) { delegate.writeFieldName(name); } } } @Override public void writeFieldId(long id) throws IOException { String idString = Long.toString(id); TokenFilter state = filterContext.setFieldName(idString); if (state == null) { itemFilter = null; } else if (state == TokenFilter.INCLUDE_ALL) { itemFilter = state; delegate.writeFieldId(id); } else { state = state.includeProperty(idString); itemFilter = state; if (state != null) { delegate.writeFieldId(id); } } } /* /********************************************************** /* Public API, write methods, text/String values /********************************************************** */ @Override public void writeString(String value) throws IOException { if (itemFilter != null) { delegate.writeString(value); } } @Override public void writeString(char[] text, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeString(text, offset, len); } } @Override public void writeString(SerializableString value) throws IOException { if (itemFilter != null) { delegate.writeString(value); } } @Override public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException { if (itemFilter != null) { delegate.writeRawUTF8String(text, offset, length); } } @Override public void writeUTF8String(byte[] text, int offset, int length) throws IOException { // not exact match, but best we can do if (itemFilter != null) { delegate.writeUTF8String(text, offset, length); } } /* /********************************************************** /* Public API, write methods, binary/raw content /********************************************************** */ @Override public void writeRaw(String text) throws IOException { if (itemFilter != null) { delegate.writeRaw(text); } } @Override public void writeRaw(String text, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeRaw(text); } } @Override public void writeRaw(SerializableString text) throws IOException { if (itemFilter != null) { delegate.writeRaw(text); } } @Override public void writeRaw(char[] text, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeRaw(text, offset, len); } } @Override public void writeRaw(char c) throws IOException { if (itemFilter != null) { delegate.writeRaw(c); } } @Override public void writeRawValue(String text) throws IOException { if (itemFilter != null) { delegate.writeRaw(text); } } @Override public void writeRawValue(String text, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeRaw(text, offset, len); } } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeRaw(text, offset, len); } } @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException { if (itemFilter != null) { delegate.writeBinary(b64variant, data, offset, len); } } @Override public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException { if (itemFilter != null) { return delegate.writeBinary(b64variant, data, dataLength); } else { return -1; } } /* /********************************************************** /* Public API, write methods, other value types /********************************************************** */ @Override public void writeNumber(short v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(int v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(long v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(BigInteger v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(double v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(float v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(BigDecimal v) throws IOException { if (itemFilter != null) { delegate.writeNumber(v); } } @Override public void writeNumber(String encodedValue) throws IOException, UnsupportedOperationException { if (itemFilter != null) { delegate.writeNumber(encodedValue); } } @Override public void writeBoolean(boolean v) throws IOException { if (itemFilter != null) { delegate.writeBoolean(v); } } @Override public void writeNull() throws IOException { if (itemFilter != null) { delegate.writeNull(); } } /* /********************************************************** /* Overridden field methods /********************************************************** */ @Override public void writeOmittedField(String fieldName) throws IOException { // Hmmh. Not sure how this would work but... if (itemFilter != null) { delegate.writeOmittedField(fieldName); } } /* /********************************************************** /* Public API, write methods, Native Ids /********************************************************** */ // 25-Mar-2015, tatu: These are tricky as they sort of predate actual filtering calls. // Let's try to use current state as a clue at least... @Override public void writeObjectId(Object id) throws IOException { if (itemFilter != null) { delegate.writeObjectId(id); } } @Override public void writeObjectRef(Object id) throws IOException { if (itemFilter != null) { delegate.writeObjectRef(id); } } @Override public void writeTypeId(Object id) throws IOException { if (itemFilter != null) { delegate.writeTypeId(id); } } }