diff --git a/transfuse-core/pom.xml b/transfuse-core/pom.xml index 47280993..10d90b11 100644 --- a/transfuse-core/pom.xml +++ b/transfuse-core/pom.xml @@ -35,8 +35,9 @@ commons-io commons-io - 2.4 + 2.5 test + org.mockito diff --git a/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerResourceWriter.java b/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerResourceWriter.java index dd5a857c..3c623cc2 100644 --- a/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerResourceWriter.java +++ b/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerResourceWriter.java @@ -24,6 +24,8 @@ import javax.tools.StandardLocation; import java.io.IOException; import java.io.OutputStream; +import java.io.Writer; +import java.nio.charset.Charset; import java.util.Collection; import java.util.HashSet; @@ -40,18 +42,17 @@ public FilerResourceWriter(Filer filer) { @Override public OutputStream openBinary(JPackage pkg, String fileName) throws IOException { FileObject resource = filer.createResource(StandardLocation.SOURCE_OUTPUT, pkg.name(), fileName); - - OutputStream os = resource.openOutputStream(); + OutputStream os = getWriterOutputStream(resource.openWriter()); openStreams.add(os); - return os; } - + public OutputStream getWriterOutputStream(Writer writer) { + return new WriterOutputStream(writer, Charset.forName("UTF-8")); + } @Override public void close() throws IOException { for (OutputStream openStream : openStreams) { - openStream.flush(); openStream.close(); } } diff --git a/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerSourceCodeWriter.java b/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerSourceCodeWriter.java index 77a82f5c..169ad591 100644 --- a/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerSourceCodeWriter.java +++ b/transfuse-core/src/main/java/org/androidtransfuse/gen/FilerSourceCodeWriter.java @@ -24,6 +24,8 @@ import javax.tools.JavaFileObject; import java.io.IOException; import java.io.OutputStream; +import java.io.Writer; +import java.nio.charset.Charset; import java.util.Collection; import java.util.HashSet; @@ -49,13 +51,16 @@ public OutputStream openBinary(JPackage jPackage, String fileName) throws IOExce //generate a source file based on package and fileName String qualified = toQualifiedClassName(jPackage, fileName); JavaFileObject sourceFile = filer.createSourceFile(qualified, originating.getOriginatingElements(qualified)); - - OutputStream os = sourceFile.openOutputStream(); + OutputStream os = getWriterOutputStream(sourceFile.openWriter()); openStreams.add(os); return os; } + public OutputStream getWriterOutputStream(Writer writer) { + return new WriterOutputStream(writer, Charset.forName("UTF-8")); + } + private String toQualifiedClassName(JPackage pkg, String fileName) { return new PackageClass(pkg.name(), fileName).getFullyQualifiedName(); } @@ -63,7 +68,6 @@ private String toQualifiedClassName(JPackage pkg, String fileName) { @Override public void close() throws IOException { for (OutputStream openStream : openStreams) { - openStream.flush(); openStream.close(); } } diff --git a/transfuse-core/src/main/java/org/androidtransfuse/gen/WriterOutputStream.java b/transfuse-core/src/main/java/org/androidtransfuse/gen/WriterOutputStream.java new file mode 100644 index 00000000..c4f6b179 --- /dev/null +++ b/transfuse-core/src/main/java/org/androidtransfuse/gen/WriterOutputStream.java @@ -0,0 +1,88 @@ +package org.androidtransfuse.gen; + + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + + +public class WriterOutputStream extends OutputStream { + + private final Writer writer; + private final CharsetDecoder decoder; + private final boolean writeImmediately; + private final ByteBuffer decoderIn; + private final CharBuffer decoderOut; + + public WriterOutputStream(Writer writer, Charset charset) { + this.decoderIn = ByteBuffer.allocate(128); + this.writer = writer; + this.decoder = charset.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE).replaceWith("?"); + this.writeImmediately = false; + this.decoderOut = CharBuffer.allocate(1024); + } + + public void write(byte[] b, int off, int len) throws IOException { + while (len > 0) { + int c = Math.min(len, this.decoderIn.remaining()); + this.decoderIn.put(b, off, c); + this.processInput(false); + len -= c; + off += c; + } + + if (this.writeImmediately) { + this.flushOutput(); + } + } + + public void write(byte[] b) throws IOException { + this.write(b, 0, b.length); + } + + public void write(int b) throws IOException { + this.write(new byte[]{(byte) b}, 0, 1); + } + + public void flush() throws IOException { + this.flushOutput(); + this.writer.flush(); + } + + public void close() throws IOException { + this.processInput(true); + this.flushOutput(); + this.writer.close(); + } + + private void processInput(boolean endOfInput) throws IOException { + this.decoderIn.flip(); + + while (true) { + CoderResult coderResult = this.decoder.decode(this.decoderIn, this.decoderOut, endOfInput); + if (!coderResult.isOverflow()) { + if (coderResult.isUnderflow()) { + this.decoderIn.compact(); + return; + } else { + throw new IOException("Unexpected coder result"); + } + } + + this.flushOutput(); + } + } + + private void flushOutput() throws IOException { + if (this.decoderOut.position() > 0) { + this.writer.write(this.decoderOut.array(), 0, this.decoderOut.position()); + this.decoderOut.rewind(); + } + } +} diff --git a/transfuse-support/pom.xml b/transfuse-support/pom.xml index a95f4e3f..d77bfe77 100644 --- a/transfuse-support/pom.xml +++ b/transfuse-support/pom.xml @@ -79,7 +79,7 @@ commons-io commons-io - 2.4 + 2.5 test diff --git a/transfuse/pom.xml b/transfuse/pom.xml index fdc67d8c..9748a49d 100644 --- a/transfuse/pom.xml +++ b/transfuse/pom.xml @@ -53,8 +53,9 @@ commons-io commons-io - 2.4 + 2.5 test + org.mockito diff --git a/transfuse/src/test/java/org/androidtransfuse/gen/FilerResourceWriterTest.java b/transfuse/src/test/java/org/androidtransfuse/gen/FilerResourceWriterTest.java index cf4d9fff..f3aaa579 100644 --- a/transfuse/src/test/java/org/androidtransfuse/gen/FilerResourceWriterTest.java +++ b/transfuse/src/test/java/org/androidtransfuse/gen/FilerResourceWriterTest.java @@ -24,6 +24,7 @@ import javax.tools.StandardLocation; import java.io.IOException; import java.io.OutputStream; +import java.io.Writer; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; @@ -31,6 +32,7 @@ /** * @author John Ericksen */ + public class FilerResourceWriterTest { private static final String TEST_PACKAGE = "org.test"; @@ -40,6 +42,7 @@ public class FilerResourceWriterTest { private Filer mockFiler; private FileObject mockFile; private OutputStream mockOutputStream; + private Writer mockWriter; private JCodeModel codeModel; @Before @@ -47,21 +50,19 @@ public void setUp() throws Exception { mockFiler = mock(Filer.class); mockFile = mock(FileObject.class); mockOutputStream = mock(OutputStream.class); + mockWriter = mock(Writer.class); - resourceWriter = new FilerResourceWriter(mockFiler); + resourceWriter = spy(new FilerResourceWriter(mockFiler)); codeModel = new JCodeModel(); } @Test public void testCreateResource() throws IOException { - when(mockFiler.createResource(StandardLocation.SOURCE_OUTPUT, TEST_PACKAGE, TEST_FILENAME)).thenReturn(mockFile); - when(mockFile.openOutputStream()).thenReturn(mockOutputStream); - + doReturn(mockWriter).when(mockFile).openWriter(); + doReturn(mockOutputStream).when(resourceWriter).getWriterOutputStream(mockWriter); assertEquals(mockOutputStream, resourceWriter.openBinary(codeModel._package(TEST_PACKAGE), TEST_FILENAME)); - resourceWriter.close(); - verify(mockOutputStream).flush(); verify(mockOutputStream).close(); } } diff --git a/transfuse/src/test/java/org/androidtransfuse/gen/FilerSourceCodeWriterTest.java b/transfuse/src/test/java/org/androidtransfuse/gen/FilerSourceCodeWriterTest.java index f15c9c3e..8df54040 100644 --- a/transfuse/src/test/java/org/androidtransfuse/gen/FilerSourceCodeWriterTest.java +++ b/transfuse/src/test/java/org/androidtransfuse/gen/FilerSourceCodeWriterTest.java @@ -19,17 +19,19 @@ import org.junit.Before; import org.junit.Test; + import javax.annotation.processing.Filer; import javax.tools.JavaFileObject; -import java.io.IOException; import java.io.OutputStream; - +import java.io.Writer; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; + /** * @author John Ericksen */ + public class FilerSourceCodeWriterTest { private static final String TEST_PACKAGE = "org.test"; @@ -39,28 +41,26 @@ public class FilerSourceCodeWriterTest { private Filer mockFiler; private JavaFileObject mockFile; private OutputStream mockOutputStream; + private Writer mockWriter; private JCodeModel codeModel; @Before public void setUp() throws Exception { + mockWriter = mock(Writer.class); mockFiler = mock(Filer.class); mockFile = mock(JavaFileObject.class); mockOutputStream = mock(OutputStream.class); - - codeWriter = new FilerSourceCodeWriter(mockFiler, new Originating()); + codeWriter = spy(new FilerSourceCodeWriter(mockFiler, new Originating())); codeModel = new JCodeModel(); } @Test - public void testCreateSourceFile() throws IOException { - + public void testCreateSourceFile() throws Exception { when(mockFiler.createSourceFile(TEST_PACKAGE + "." + TEST_CLASS)).thenReturn(mockFile); - when(mockFile.openOutputStream()).thenReturn(mockOutputStream); - + doReturn(mockWriter).when(mockFile).openWriter(); + doReturn(mockOutputStream).when(codeWriter).getWriterOutputStream(mockWriter); assertEquals(mockOutputStream, codeWriter.openBinary(codeModel._package(TEST_PACKAGE), TEST_CLASS)); - codeWriter.close(); - verify(mockOutputStream).flush(); verify(mockOutputStream).close(); } }