Skip to content

Commit 6558c49

Browse files
Mehdi Kaytouesurli
Mehdi Kaytoue
authored andcommitted
feat: Use Apache Common Compressor API to [de]compress serialized models (#2165)
Since #2094 and #2103 we can [de]serialize the model (CtFactory) with standard java serialization in a file, or a gzip file to save space. Choice was made to write things so that we can add new compression types easily. In this PR, I propose to use Apache Common Compressor API (+other files needed for some compression types such as LZMA). Main changes in src/main/java/spoon/support/SerializationModelStreamer.java and its junit test case src/test/java/spoon/test/serializable/ModelStreamerTest.java and of course pom.xml. I don't know what you think about adding a new lib, but this lib allows very easily (i) to test what compressor is used for an inputstream (except 7zip btw), (ii) to decompress, (iii) to compress. Looking forward discussing it with you guyz :) Cheers, Mehdi
1 parent 3337e32 commit 6558c49

File tree

4 files changed

+87
-35
lines changed

4 files changed

+87
-35
lines changed

pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,23 @@
268268
<artifactId>commons-lang3</artifactId>
269269
<version>3.5</version>
270270
</dependency>
271+
<!-- https://mvnrepository.com/artifact/org.tukaani/xz -->
272+
<dependency>
273+
<groupId>org.tukaani</groupId>
274+
<artifactId>xz</artifactId>
275+
<version>1.8</version>
276+
</dependency>
271277
<dependency>
272278
<groupId>com.fasterxml.jackson.core</groupId>
273279
<artifactId>jackson-databind</artifactId>
274280
<version>2.9.5</version>
275281
</dependency>
282+
<dependency>
283+
<!-- support for compressed serialized ASTs -->
284+
<groupId>org.apache.commons</groupId>
285+
<artifactId>commons-compress</artifactId>
286+
<version>1.17</version>
287+
</dependency>
276288
<dependency>
277289
<!-- to reproduce JTD error with nullable annotation -->
278290
<groupId>com.google.guava</groupId>

src/main/java/spoon/support/CompressionType.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
* @see SerializationModelStreamer
2222
*/
2323
public enum CompressionType {
24-
2524
NONE,
26-
GZIP;
27-
25+
GZIP,
26+
LZMA,
27+
BZIP2;
2828
}

src/main/java/spoon/support/SerializationModelStreamer.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
import java.util.zip.GZIPInputStream;
2727
import java.util.zip.GZIPOutputStream;
2828

29+
import org.apache.commons.compress.compressors.CompressorException;
30+
import org.apache.commons.compress.compressors.CompressorStreamFactory;
31+
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
32+
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
33+
import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
34+
import org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream;
35+
2936
import spoon.Launcher;
3037
import spoon.reflect.ModelStreamer;
3138
import spoon.reflect.declaration.CtElement;
@@ -48,6 +55,10 @@ public SerializationModelStreamer() {
4855
public void save(Factory f, OutputStream out) throws IOException {
4956
if (f.getEnvironment().getCompressionType() == CompressionType.GZIP) {
5057
out = new GZIPOutputStream(out);
58+
} else if (f.getEnvironment().getCompressionType() == CompressionType.LZMA) {
59+
out = new LZMACompressorOutputStream(out);
60+
} else if (f.getEnvironment().getCompressionType() == CompressionType.BZIP2) {
61+
out = new BZip2CompressorOutputStream(out);
5162
}
5263
try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(out))) {
5364
oos.writeObject(f);
@@ -57,19 +68,21 @@ public void save(Factory f, OutputStream out) throws IOException {
5768

5869
@Override
5970
public Factory load(InputStream in) throws IOException {
60-
if (!in.markSupported()) {
61-
in = new BufferedInputStream(in);
62-
}
63-
// Check if it is a GZIP
64-
in.mark(2);
65-
int ch1 = in.read();
66-
int ch2 = in.read();
67-
int header = ((ch2 << 8) + (ch1 << 0));
68-
in.reset();
69-
if (header == GZIPInputStream.GZIP_MAGIC) {
70-
in = new GZIPInputStream(in);
71-
}
72-
try (ObjectInputStream ois = new ObjectInputStream(in)) {
71+
try {
72+
BufferedInputStream buffered = new BufferedInputStream(in);
73+
try {
74+
String s = CompressorStreamFactory.detect(buffered);
75+
if (s.equals(CompressorStreamFactory.GZIP)) {
76+
in = new GZIPInputStream(buffered);
77+
} else if (s.equals(CompressorStreamFactory.LZMA)) {
78+
in = new LZMACompressorInputStream(buffered);
79+
} else if (s.equals(CompressorStreamFactory.BZIP2)) {
80+
in = new BZip2CompressorInputStream(buffered);
81+
}
82+
} catch (CompressorException e) {
83+
in = buffered;
84+
}
85+
ObjectInputStream ois = new ObjectInputStream(in);
7386
final Factory f = (Factory) ois.readObject();
7487
//create query using factory directly
7588
//because any try to call CtElement#map or CtElement#filterChildren will fail on uninitialized factory

src/test/java/spoon/test/serializable/ModelStreamerTest.java

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import java.util.List;
2727
import java.util.stream.Collectors;
2828

29-
import org.junit.Before;
29+
import org.junit.BeforeClass;
3030
import org.junit.Test;
3131

3232
import spoon.Launcher;
@@ -38,42 +38,69 @@
3838

3939
public class ModelStreamerTest {
4040

41-
private final String filename = "./src/test/resources/serialization/factory.ser";
41+
private static final String SOURCE_DIRECTORY = "./src/main/java/spoon/reflect/declaration";
42+
private final static String OUTPUT_FILENAME = "./src/test/resources/serialization/factory.ser";
43+
private static File outputFile;
44+
private static Factory factory;
4245

43-
private Factory factory;
44-
45-
private File file;
46-
47-
@Before
48-
public void setUp() {
46+
@BeforeClass
47+
public static void setUp() {
48+
System.out.println("Testing factory serialization with different "
49+
+ "compressors with source folder: " + SOURCE_DIRECTORY);
4950
Launcher launcher = new Launcher();
50-
launcher.addInputResource("./src/main/java/spoon/reflect/declaration");
51+
launcher.addInputResource(SOURCE_DIRECTORY);
5152
launcher.buildModel();
52-
this.factory = launcher.getFactory();
53-
file = new File(filename);
54-
file.deleteOnExit();
53+
factory = launcher.getFactory();
54+
outputFile = new File(OUTPUT_FILENAME);
55+
outputFile.deleteOnExit();
5556
}
5657

5758
@Test
5859
public void testDefaultCompressionType() throws IOException {
59-
new SerializationModelStreamer().save(factory, new FileOutputStream(file));
60-
Factory factoryFromFile = new SerializationModelStreamer().load(new FileInputStream(file));
60+
new SerializationModelStreamer().save(factory, new FileOutputStream(outputFile));
61+
FileInputStream in = new FileInputStream(outputFile);
62+
System.out.println(in.getChannel().size() + " bytes for default");
63+
Factory factoryFromFile = new SerializationModelStreamer().load(in);
6164
compareFactoryModels(factory, factoryFromFile);
6265
}
63-
66+
6467
@Test
6568
public void testGZipCompressionType() throws IOException {
6669
factory.getEnvironment().setCompressionType(CompressionType.GZIP);
67-
new SerializationModelStreamer().save(factory, new FileOutputStream(file));
68-
Factory factoryFromFile = new SerializationModelStreamer().load(new FileInputStream(file));
70+
new SerializationModelStreamer().save(factory, new FileOutputStream(outputFile));
71+
FileInputStream in = new FileInputStream(outputFile);
72+
System.out.println(in.getChannel().size() + " bytes for " + CompressionType.GZIP);
73+
Factory factoryFromFile = new SerializationModelStreamer().load(in);
74+
compareFactoryModels(factory, factoryFromFile);
75+
}
76+
77+
@Test
78+
public void testBZip2CompressionType() throws IOException {
79+
factory.getEnvironment().setCompressionType(CompressionType.BZIP2);
80+
new SerializationModelStreamer().save(factory, new FileOutputStream(outputFile));
81+
FileInputStream in = new FileInputStream(outputFile);
82+
System.out.println(in.getChannel().size() + " bytes for " + CompressionType.BZIP2);
83+
Factory factoryFromFile = new SerializationModelStreamer().load(in);
6984
compareFactoryModels(factory, factoryFromFile);
7085
}
7186

7287
@Test
7388
public void testNoneCompressionType() throws IOException {
7489
factory.getEnvironment().setCompressionType(CompressionType.NONE);
75-
new SerializationModelStreamer().save(factory, new FileOutputStream(file));
76-
Factory factoryFromFile = new SerializationModelStreamer().load(new FileInputStream(file));
90+
new SerializationModelStreamer().save(factory, new FileOutputStream(outputFile));
91+
FileInputStream in = new FileInputStream(outputFile);
92+
System.out.println(in.getChannel().size() + " bytes for " + CompressionType.NONE);
93+
Factory factoryFromFile = new SerializationModelStreamer().load(in);
94+
compareFactoryModels(factory, factoryFromFile);
95+
}
96+
97+
@Test
98+
public void testLZMACompressionType() throws IOException {
99+
factory.getEnvironment().setCompressionType(CompressionType.LZMA);
100+
new SerializationModelStreamer().save(factory, new FileOutputStream(outputFile));
101+
FileInputStream in = new FileInputStream(outputFile);
102+
System.out.println(in.getChannel().size() + " bytes for " + CompressionType.LZMA);
103+
Factory factoryFromFile = new SerializationModelStreamer().load(in);
77104
compareFactoryModels(factory, factoryFromFile);
78105
}
79106

0 commit comments

Comments
 (0)