1515 */
1616package com .google .testing .compile ;
1717
18+ import static com .google .common .collect .MoreCollectors .toOptional ;
19+
1820import com .google .common .base .MoreObjects ;
1921import com .google .common .base .Optional ;
2022import com .google .common .cache .CacheBuilder ;
3234import java .io .Writer ;
3335import java .net .URI ;
3436import java .nio .charset .Charset ;
35- import java .util .Map .Entry ;
37+ import java .util .HashMap ;
38+ import java .util .Map ;
3639import javax .tools .FileObject ;
3740import javax .tools .JavaFileObject ;
3841import javax .tools .JavaFileObject .Kind ;
4750 */
4851// TODO(gak): under java 1.7 this could all be done with a PathFileManager
4952final class InMemoryJavaFileManager extends ForwardingStandardJavaFileManager {
50- private final LoadingCache <URI , JavaFileObject > inMemoryFileObjects =
51- CacheBuilder .newBuilder ().build (new CacheLoader <URI , JavaFileObject >() {
52- @ Override
53- public JavaFileObject load (URI key ) {
54- return new InMemoryJavaFileObject (key );
55- }
56- });
53+ private final LoadingCache <URI , JavaFileObject > inMemoryOutputs =
54+ CacheBuilder .newBuilder ()
55+ .build (
56+ new CacheLoader <URI , JavaFileObject >() {
57+ @ Override
58+ public JavaFileObject load (URI key ) {
59+ return new InMemoryJavaFileObject (key );
60+ }
61+ });
62+
63+ private final Map <URI , JavaFileObject > inMemoryInputs = new HashMap <>();
5764
5865 InMemoryJavaFileManager (StandardJavaFileManager fileManager ) {
5966 super (fileManager );
@@ -86,40 +93,64 @@ public boolean isSameFile(FileObject a, FileObject b) {
8693 public FileObject getFileForInput (Location location , String packageName ,
8794 String relativeName ) throws IOException {
8895 if (location .isOutputLocation ()) {
89- return inMemoryFileObjects .getIfPresent (
90- uriForFileObject (location , packageName , relativeName ));
91- } else {
92- return super .getFileForInput (location , packageName , relativeName );
96+ return inMemoryOutputs .getIfPresent (uriForFileObject (location , packageName , relativeName ));
9397 }
98+ Optional <JavaFileObject > inMemoryInput = findInMemoryInput (packageName , relativeName );
99+ if (inMemoryInput .isPresent ()) {
100+ return inMemoryInput .get ();
101+ }
102+ return super .getFileForInput (location , packageName , relativeName );
94103 }
95104
96105 @ Override
97106 public JavaFileObject getJavaFileForInput (Location location , String className , Kind kind )
98107 throws IOException {
99108 if (location .isOutputLocation ()) {
100- return inMemoryFileObjects .getIfPresent (uriForJavaFileObject (location , className , kind ));
101- } else {
102- return super .getJavaFileForInput (location , className , kind );
109+ return inMemoryOutputs .getIfPresent (uriForJavaFileObject (location , className , kind ));
110+ }
111+ Optional <JavaFileObject > inMemoryInput = findInMemoryInput (className );
112+ if (inMemoryInput .isPresent ()) {
113+ return inMemoryInput .get ();
103114 }
115+ return super .getJavaFileForInput (location , className , kind );
116+ }
117+
118+ private Optional <JavaFileObject > findInMemoryInput (String className ) {
119+ int lastDot = className .lastIndexOf ('.' );
120+ return findInMemoryInput (
121+ lastDot == -1 ? "" : className .substring (0 , lastDot - 1 ),
122+ className .substring (lastDot + 1 ) + ".java" );
123+ }
124+
125+ private Optional <JavaFileObject > findInMemoryInput (String packageName , String relativeName ) {
126+ // Assume each input file's URI ends with the package/relative name. It might have other parts
127+ // to the left.
128+ String suffix =
129+ packageName .isEmpty () ? relativeName : packageName .replace ('.' , '/' ) + "/" + relativeName ;
130+ return Optional .fromJavaUtil (
131+ inMemoryInputs .entrySet ().stream ()
132+ .filter (entry -> entry .getKey ().getPath ().endsWith (suffix ))
133+ .map (Map .Entry ::getValue )
134+ .collect (toOptional ())); // Might have problems if more than one input file matches.
104135 }
105136
106137 @ Override
107138 public FileObject getFileForOutput (Location location , String packageName ,
108139 String relativeName , FileObject sibling ) throws IOException {
109140 URI uri = uriForFileObject (location , packageName , relativeName );
110- return inMemoryFileObjects .getUnchecked (uri );
141+ return inMemoryOutputs .getUnchecked (uri );
111142 }
112143
113144 @ Override
114145 public JavaFileObject getJavaFileForOutput (Location location , String className , final Kind kind ,
115146 FileObject sibling ) throws IOException {
116147 URI uri = uriForJavaFileObject (location , className , kind );
117- return inMemoryFileObjects .getUnchecked (uri );
148+ return inMemoryOutputs .getUnchecked (uri );
118149 }
119150
120151 ImmutableList <JavaFileObject > getGeneratedSources () {
121152 ImmutableList .Builder <JavaFileObject > result = ImmutableList .builder ();
122- for (Entry <URI , JavaFileObject > entry : inMemoryFileObjects .asMap ().entrySet ()) {
153+ for (Map . Entry <URI , JavaFileObject > entry : inMemoryOutputs .asMap ().entrySet ()) {
123154 if (entry .getKey ().getPath ().startsWith ("/" + StandardLocation .SOURCE_OUTPUT .name ())
124155 && (entry .getValue ().getKind () == Kind .SOURCE )) {
125156 result .add (entry .getValue ());
@@ -129,7 +160,14 @@ ImmutableList<JavaFileObject> getGeneratedSources() {
129160 }
130161
131162 ImmutableList <JavaFileObject > getOutputFiles () {
132- return ImmutableList .copyOf (inMemoryFileObjects .asMap ().values ());
163+ return ImmutableList .copyOf (inMemoryOutputs .asMap ().values ());
164+ }
165+
166+ /** Adds files that should be available in the source path. */
167+ void addSourceFiles (Iterable <? extends JavaFileObject > files ) {
168+ for (JavaFileObject file : files ) {
169+ inMemoryInputs .put (file .toUri (), file );
170+ }
133171 }
134172
135173 private static final class InMemoryJavaFileObject extends SimpleJavaFileObject
0 commit comments