package com.kryptnostic.kodex.v1.marshalling; import java.io.IOException; import java.nio.ByteBuffer; import java.util.zip.DataFormatException; import java.util.zip.Deflater; import java.util.zip.Inflater; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Preconditions; import com.kryptnostic.kodex.v1.serialization.jackson.KodexObjectMapperFactory; public class DeflatingJacksonMarshaller { private final ObjectMapper mapper = KodexObjectMapperFactory.getObjectMapper(); protected static final int INTEGER_BYTES = Integer.SIZE / Byte.SIZE; public <T> T fromBytes( byte[] bytes , Class<T> reference) throws IOException { final Inflater inflater = new Inflater(); ByteBuffer in = ByteBuffer.wrap( bytes ); int uncompressedLength = in.getInt(); byte[] compressedBytes = new byte[ bytes.length - INTEGER_BYTES ]; byte[] uncompressedBytes = new byte[ uncompressedLength ]; in.get( compressedBytes ); inflater.setInput( compressedBytes ); int resultingLength = 0; try { resultingLength = inflater.inflate( uncompressedBytes ); } catch ( DataFormatException e ) { throw new IOException( e ); } Preconditions.checkState( resultingLength == uncompressedLength, "Expected length and decompressed length do not match." ); return mapper.readValue( uncompressedBytes, reference ); } public<T> T fromBytes( byte[] bytes , TypeReference<T> reference) throws IOException { final Inflater inflater = new Inflater(); ByteBuffer in = ByteBuffer.wrap( bytes ); int uncompressedLength = in.getInt(); byte[] compressedBytes = new byte[ bytes.length - INTEGER_BYTES ]; byte[] uncompressedBytes = new byte[ uncompressedLength ]; in.get( compressedBytes ); inflater.setInput( compressedBytes ); int resultingLength = 0; try { resultingLength = inflater.inflate( uncompressedBytes ); } catch ( DataFormatException e ) { throw new IOException( e ); } Preconditions.checkState( resultingLength == uncompressedLength, "Expected length and decompressed length do not match." ); return mapper.readValue( uncompressedBytes, reference ); } public byte[] toBytes( Object object ) throws IOException { final Deflater deflater = new Deflater( Deflater.BEST_COMPRESSION ); byte[] input = mapper.writeValueAsBytes( object ); byte[] output = new byte[ input.length << 1 ]; deflater.setInput( input ); deflater.finish(); int compressedBytes = deflater.deflate( output, 0, output.length, Deflater.FULL_FLUSH ); ByteBuffer o = ByteBuffer.allocate( INTEGER_BYTES + compressedBytes ); o.putInt( input.length ); o.put( output, 0, compressedBytes ); return o.array(); } }