[ 
https://issues.apache.org/jira/browse/GROOVY-12711?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Daniel Sun updated GROOVY-12711:
--------------------------------
    Description: 
h2. Summary

With {{memStub}} and {{memClassOutput}} both set to {{Boolean.TRUE}}, joint 
compilation keeps the generated Java stubs and the class files on the heap. The 
class files are published on the compilation class loader, and the compile 
needs neither a stub directory nor a class-output directory.

h2. Background

Joint compilation can already keep generated Java stubs in memory. The joint 
option {{memStub}} ({{CompilerConfiguration.MEM_STUB}}) has been available 
since 3.0.0. {{JavaAwareCompilationUnit}} writes those stubs at 
{{Phases.CONVERSION}}, including signatures contributed by GEP-21 transforms, 
and runs javac at {{Phases.SEMANTIC_ANALYSIS}}.

Class files were the remaining disk step. Javac wrote {{CLASS_OUTPUT}} to a 
target directory, so the core API could not keep both the stubs and the class 
files off disk.

{{memClassOutput}} adds that step. It takes effect only together with 
{{memStub}}, and the compilation class loader publishes the class files. 
{{groovy-lsp}} does not set the option. It still uses its own Java compiler and 
an owner-only temporary directory for javac output.

h2. Motivation

* Tests, IDEs, and agent tools that edit Groovy and Java together need a joint 
compile that does not write stubs or class files into the project tree or into 
a temporary directory that must be locked down and removed.
* A stub directory and a class-output directory add latency, race with file 
watchers, and can disagree with the sources the compiler just parsed.
* In-memory stubs were already available. Keeping the class files in memory as 
well completes the joint cycle inside groovy-core. Later introspection tools 
can build on that cycle, and those tools remain separate work.

h2. Goals

* {{memClassOutput}} ({{CompilerConfiguration.MEM_CLASS_OUTPUT}}) is an 
explicit joint option, new in 7.0.0. It is honored only when {{memStub}} is 
also {{Boolean.TRUE}}. A missing target directory does not turn it on.
* With both options set, {{JavaAwareCompilationUnit}} and the default javac 
compiler finish a mixed Groovy and Java compile with no {{stubDir}} and no 
filesystem target directory. The class bytes are published on the compilation 
class loader. Resolution reads that loader, in the order described under "What 
callers should expect".
* {{groovyc}} and the Ant task leave the option unset, so disk {{stubDir}} and 
target-directory output remain the default.
* The joint-compilation section of the groovyc guide documents {{memStub}} and 
{{memClassOutput}}.
* Callers enable this through {{CompilerConfiguration}} and 
{{JavaAwareCompilationUnit}}. The file manager that stores the bytes is 
package-private, in {{org.codehaus.groovy.tools.javac}}.
* Tests show a Groovy and Java cycle with no stub directory and no class-output 
directory, a javac type error on that path, and the unchanged disk path.

h2. Non-Goals

* groovy-core does not gain an MCP server, a JSON-RPC API, or an MCP library, 
and it does not change the LSP protocol.
* {{groovy-lsp}} and {{groovy-mcp}} stay as they are. {{groovy-lsp}} still uses 
its own Java compiler and an owner-only temporary directory. Only 
{{JavacJavaCompiler}} implements {{memClassOutput}}, so using the option there 
is separate work.
* This issue does not add an overlay filesystem or a multi-tenant sandbox.
* Dynamic Groovy is not switched over to static type checking.
* Builds that leave the option unset keep disk {{stubDir}} and target-directory 
output. The system property {{groovy.mem.stub}} enables in-memory stubs only.
* GEP-21 stub generation, including {{MemJavaFileObject}}, stays as it is. 
Signature changes that must be visible to javac still come from the GEP-21 
{{Phases.CONVERSION}} stubbers. Other AST transforms are not moved ahead of 
stub emission.

h2. Enabling the option

{{memClassOutput}} ({{CompilerConfiguration.MEM_CLASS_OUTPUT}}) is new in 
7.0.0. {{CompilerConfiguration.isMemClassOutput()}} is true only when 
{{memStub}} ({{CompilerConfiguration.MEM_STUB}}) and {{memClassOutput}} are 
both {{Boolean.TRUE}}.

{code:java}
CompilerConfiguration config = new CompilerConfiguration();
Map<String, Object> options = new HashMap<>();
options.put(CompilerConfiguration.MEM_STUB, Boolean.TRUE);
options.put(CompilerConfiguration.MEM_CLASS_OUTPUT, Boolean.TRUE);
config.setJointCompilationOptions(options);
{code}

* {{memClassOutput}} without {{memStub}} fails the compile with 
{{memClassOutput requires memStub}}. The system property {{groovy.mem.stub}} 
enables {{memStub}} only.
* Only {{JavacJavaCompiler}} implements the option. Any other {{JavaCompiler}} 
fails the compile with {{memClassOutput requires the default javac joint 
compiler}}. Using that javac implementation with a plain {{CompilationUnit}} 
fails the compile with {{memClassOutput requires JavaAwareCompilationUnit}}.
* When both options are set, {{stubDir}} is not required. The compiler does not 
add {{-d}}. If the joint options still pass {{-d}}, the file manager consumes 
it and keeps the class files in memory. {{targetDirectory}} is not added to the 
compilation class loader, because an earlier classpath entry would hide those 
classes.

h2. How classes are published

{{JavaAwareCompilationUnit}} captures javac {{CLASS_OUTPUT}} with 
{{InMemoryJavaFileManager}}, in package {{org.codehaus.groovy.tools.javac}}, 
when javac runs. It writes the Groovy class files from the same compile into 
that same map during output. Classpath and source input still come from the 
standard file manager. The manager does no network I/O. The file manager and 
the classpath store are package-private; callers enable the behavior with the 
joint option above.

One URL attaches the map to the compilation {{GroovyClassLoader}}:

* The protocol is {{x-groovy-mem}} and the host is empty, so hashing or 
comparing the {{URL}} does not look up a DNS name. On the Java 17 baseline a 
security manager can still require {{NetPermission("specifyStreamHandler")}} to 
install the handler.
* The protocol is not registered with the JVM. Only URLs created for this 
classpath can be opened. A path that escapes the map is rejected. A plus sign 
in a resource name stays a plus sign.
* The URL is appended to the loader. {{URLClassLoader}} cannot remove a URL, so 
another {{JavaAwareCompilationUnit}} on the same loader reuses the store. 
{{groovyc}} and the Ant task build one unit per run.

The unit opens one stage on that store. Lookup prefers the stage and otherwise 
returns the last committed bytes. A class written during this compile is 
visible to later phases. A class this compile has not written is still read 
from the previous commit, when one exists.

The stage is committed when {{compile}} returns normally after class output has 
completed. Commit adds and replaces entries and leaves every other name as it 
was. A failed compile discards the stage, and the previously committed classes 
stay in place.

A compile that stops at semantic analysis leaves the stage open. Javac has 
already run by then. A later {{compile}} on the same unit reuses the stage and 
does not start javac again. A different unit cannot publish while that stage is 
open: its {{compile}} throws {{IllegalStateException}} with the message 
{{another compilation is publishing to this class loader}}.

h2. What callers should expect

* A later successful compile replaces the stored bytes of each class it writes. 
{{loadClass}} returns the class the loader has already defined. A fresh loader 
is required to run the new bytes.
* Lookup searches the parent loader first, then URLs in insertion order. The 
in-memory URL is last. A parent loader or an earlier classpath entry is what 
resolution and {{getResource}} see. Commit does not change that order, so the 
earlier entry still hides the bytes.
* The compile records a warning at {{WarningMessage.LIKELY_ERRORS}}, which the 
default warning level includes. The warning text contains {{hidden by}}. Type 
checking uses the visible class. The hidden bytes are committed only when that 
compile succeeds. A failure discards the stage.
* Class files that javac produces for the Groovy stubs stay inside javac and 
are not published. The stub is an input to javac.
* Annotation processing is turned off with {{-proc:none}} unless the joint 
options request {{processor}}, {{processorpath}}, {{processor-module-path}}, 
{{proc}}, or a flag whose name starts with {{proc:}}. Generated Java sources 
({{SOURCE_OUTPUT}}) and non-class {{CLASS_OUTPUT}} resources stay in memory. 
Module-oriented file-manager locations are not supported.
* {{import module}} skips loader URLs whose protocol is not {{file}}. The 
groovysh package scan ignores a URL that is neither a file nor a jar, instead 
of failing the listing. The console classpath dialog lists {{file}} URLs only. 
The in-memory URL is left out of all three.
* The decompiler caches class stubs for {{file}}, {{jar}}, and {{jrt}} URLs 
only. The in-memory URL keeps a stable identity while its bytes can change, so 
those bytes are read again on the next lookup.

h2. Tests

{{MemClassOutputTest}} and {{InMemoryJavaFileManagerTest}} cover:

* a Groovy and Java cycle with no stub directory and no class-output directory, 
including a type error reported from javac
* disk {{stubDir}} with the option off, and {{memStub}} alone still writing the 
target directory
* {{memClassOutput}} without {{memStub}}, a joint compiler other than javac, 
and javac invoked on a plain {{CompilationUnit}}
* a second unit on the same loader, a unit opened while a stage is still open, 
and a failed recompile that keeps the last committed bytes
* a compile stopped at semantic analysis and then finished on the same unit, 
classes a later compile does not write again, and stub class files left 
unpublished
* {{import module}}, a shadowed classpath entry, and a class the loader has 
already defined
* a plus sign in a resource name, a path that escapes the map, and generated 
Java sources kept in memory


  was:
h2. Background

Apache Groovy's joint compilation pipeline already supports generating Java 
stubs in memory via {{CompilerConfiguration.MEM_STUB}} ({{"memStub"}}) and 
{{MemJavaFileObject}} (since 3.0.0). {{JavaAwareCompilationUnit}} emits those 
stubs at {{Phases.CONVERSION}} (including GEP-21 CONVERSION-phase 
transform/stubber contributions) and invokes javac at the {{SEMANTIC_ANALYSIS}} 
boundary.

What remains disk-bound is javac *class output*: {{JavacJavaCompiler}} / 
consumers such as {{groovy-lsp}} still rely on a filesystem target directory 
(or an owner-only temporary directory) for {{CLASS_OUTPUT}}. Embeddings that 
need a clean, low-latency, no-workspace-pollution joint compile—language 
services, tests, and future agent tooling—therefore cannot yet run a fully 
heap-resident Groovy↔Java cycle through the public core APIs alone.

This ticket is intentionally *not* a request to add an MCP server or LSP host 
to groovy-core. Optional modules {{groovy-lsp}} and {{groovy-mcp}} already 
provide protocol adapters over {{GroovyLanguageEngine}}. Core should supply 
reusable joint-compilation primitives those modules (and third parties) can 
adopt later.

h2. Motivation

 * Agents and IDEs that patch Groovy and Java together need joint validation 
without writing stubs or {{.class}} files into the project tree or into temp 
directories that must be permission-hardened and cleaned up.
 * Disk stub/class I/O adds latency, races with file watchers, and 
false-positive failures when overlays disagree with on-disk sources.
 * Completing in-memory *class* output—on top of existing in-memory *stub* 
sources—closes the remaining gap in the joint pipeline and unblocks follow-on 
introspection work without widening the core attack surface.

h2. Goals

 * Provide a reusable in-memory {{javax.tools.JavaFileManager}} (wrapping 
{{StandardJavaFileManager}} as needed) that stores javac {{CLASS_OUTPUT}} bytes 
in heap.
 * Integrate it into the joint-compilation path behind an *explicit opt-in* 
when {{memStub}} is enabled (recommended joint option constant alongside 
{{MEM_STUB}}, e.g. {{MEM_CLASS_OUTPUT}} / {{"memClassOutput"}}—final name 
bikeshed OK if documented).
 * Allow {{JavaAwareCompilationUnit}} + {{JavacJavaCompiler}} to complete a 
mixed Groovy/Java compile *without* requiring {{stubDir}} or a filesystem 
{{targetDirectory}} for class output when that opt-in is active.
 * Preserve today's disk-based {{stubDir}} / target-directory behavior as the 
default for Ant/Gradle-style joint builds.
 * Document the option next to {{MEM_STUB}}; mark new APIs {{@since 6.0.0}} (or 
the assigned 6.0.x).
 * Add focused unit tests proving a bidirectional Groovy↔Java reference 
compiles successfully with no stub or class files on disk, plus a regression 
that the classic disk path still works.

h2. Non-Goals

 * No MCP JSON-RPC tools, daemon, or dependency on an MCP SDK in core.
 * No LSP protocol changes and no requirement to modify {{groovy-lsp}} / 
{{groovy-mcp}} in the same change set (follow-up tickets may consume the API).
 * No Overlay VFS process, no multi-tenant sandbox service.
 * No silent forced {{StaticTypeCheckingVisitor}} on dynamic Groovy.
 * No change to default joint-compilation outputs for existing builds that do 
not opt in.
 * No attempt to run all AST transforms before stub emission (GEP-21 stubbers 
remain the mechanism for pre-javac signature contributions).
 * No "zero hallucination" product claims; success is measured by tests, 
compatibility, and API clarity.

h2. Proposed Approach

 # Add {{InMemoryJavaFileManager}} under {{org.codehaus.groovy.tools.javac}} 
that forwards to the standard manager for inputs/classpath but redirects 
{{getJavaFileForOutput(..., CLASS_OUTPUT, ...)}} to an in-memory 
{{JavaFileObject}} (e.g. {{MemClassFileObject}}), exposing produced bytecode by 
binary name.
 # Teach {{JavacJavaCompiler}} to install that manager when {{memStub}} is true 
*and* the new mem-class-output option is enabled (and/or when no target 
directory is configured—behavior must be documented and tested).
 # Adjust {{JavaAwareCompilationUnit}} configuration so the Groovy class loader 
can resolve types from the in-memory class bytes after javac without requiring 
{{targetDirectory}} on disk in that mode. Prefer the smallest robust hook; if a 
dedicated {{ClassNodeResolver}} helper is too large for one review, land 
bytecode retrieval + tested {{defineClass}}/loader integration first and file a 
follow-up for resolver sugar.
 # Keep {{MemJavaFileObject}} stub generation as-is; this ticket does not 
replace GEP-21.
 # Update package documentation for joint compilation accordingly.

h2. Acceptance Criteria

 * Standards: Uses public {{javax.tools}} APIs only (no illegal reflective 
access / {{--add-exports}} requirements beyond what Groovy already needs for 
joint compile).
 * Compatibility: Existing {{stubDir}} joint compiles without the new option 
behave as today (regression test).
 * Functional: With {{memStub}} + mem class output, a fixture where Java calls 
a Groovy stubbed API and Groovy references a Java type compiles successfully 
with no stub directory and no class-output directory.
 * Maintainability: New types live in {{org.codehaus.groovy.tools.javac}}, are 
documented, and do not entangle protocol modules.
 * Reusability: File manager API is usable by embeddings outside Ant (tests 
demonstrate construction without {{FileSystemCompiler}}).
 * Robustness: Compiler errors surface through existing collectors/diagnostics; 
failures do not leave orphan temp dirs (because none are required in the mem 
path).
 * Performance: Small fixture completes reliably under CI; mem path must not be 
pathologically slower than disk path for that fixture (guard with a generous 
timeout rather than a flaky microbenchmark).
 * Security: Output path does not write class bytes to the filesystem; does not 
introduce network I/O, script evaluation, or Grab; does not expand classpath 
resolution beyond existing joint-compile behavior. Vuln/scanner surface must 
not increase.

h2. Risks / Compatibility

 * Binary compatibility: additive APIs only; run the project's 
binary-compatibility checks.
 * Class loader / resolution ordering: in-memory classes must become visible to 
Groovy resolution the same way disk {{targetDirectory}} classes are today; 
mishandling could break joint cycles—tests must cover the bidirectional case.
 * Opt-in flag vs implied behavior when {{targetDirectory == null}}: choose one 
documented rule to avoid surprising Ant users.
 * Follow-on modules (LSP) currently create owner-only temp dirs; migrating 
them is *out of scope* here but should become easier once this lands.

h2. Test Plan

 * New unit/integration tests under the existing joint-compilation / 
tools.javac test areas:
 ** memStub + mem class output: Groovy↔Java cycle, assert success, assert no 
stubDir/class output dir required.
 ** intentional type error: failure reported cleanly.
 ** disk stubDir path unchanged when option off.
 * Run standard core test task(s) and binary-compatibility checks required for 
the touched modules.

h2. Notes for implementers / reviewers

 * Related in-tree pieces: {{MemJavaFileObject}}, 
{{JavaStubGenerator#generateMemStub}}, {{CompilerConfiguration.MEM_STUB}}, 
{{JavaAwareCompilationUnit}}, GEP-21 {{StubberSupport}}, 
{{subprojects/groovy-lsp}} ({{LspJavaCompiler}}, temp CLASS_OUTPUT), 
{{subprojects/groovy-mcp}} (protocol only—do not expand in this ticket).
 * Long-term "Semantic Oracle" agent tools (FQN contract inspect, multi-file 
dry-run, diagnostic enrichment) depend on *this* foundation plus later library 
introspection APIs; track those as separate issues after this Improvement 
merges.


> Joint compilation: keep javac CLASS_OUTPUT in memory when memStub is enabled
> ----------------------------------------------------------------------------
>
>                 Key: GROOVY-12711
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12711
>             Project: Groovy
>          Issue Type: Improvement
>          Components: Compiler
>            Reporter: Daniel Sun
>            Assignee: Daniel Sun
>            Priority: Major
>
> h2. Summary
> With {{memStub}} and {{memClassOutput}} both set to {{Boolean.TRUE}}, joint 
> compilation keeps the generated Java stubs and the class files on the heap. 
> The class files are published on the compilation class loader, and the 
> compile needs neither a stub directory nor a class-output directory.
> h2. Background
> Joint compilation can already keep generated Java stubs in memory. The joint 
> option {{memStub}} ({{CompilerConfiguration.MEM_STUB}}) has been available 
> since 3.0.0. {{JavaAwareCompilationUnit}} writes those stubs at 
> {{Phases.CONVERSION}}, including signatures contributed by GEP-21 transforms, 
> and runs javac at {{Phases.SEMANTIC_ANALYSIS}}.
> Class files were the remaining disk step. Javac wrote {{CLASS_OUTPUT}} to a 
> target directory, so the core API could not keep both the stubs and the class 
> files off disk.
> {{memClassOutput}} adds that step. It takes effect only together with 
> {{memStub}}, and the compilation class loader publishes the class files. 
> {{groovy-lsp}} does not set the option. It still uses its own Java compiler 
> and an owner-only temporary directory for javac output.
> h2. Motivation
> * Tests, IDEs, and agent tools that edit Groovy and Java together need a 
> joint compile that does not write stubs or class files into the project tree 
> or into a temporary directory that must be locked down and removed.
> * A stub directory and a class-output directory add latency, race with file 
> watchers, and can disagree with the sources the compiler just parsed.
> * In-memory stubs were already available. Keeping the class files in memory 
> as well completes the joint cycle inside groovy-core. Later introspection 
> tools can build on that cycle, and those tools remain separate work.
> h2. Goals
> * {{memClassOutput}} ({{CompilerConfiguration.MEM_CLASS_OUTPUT}}) is an 
> explicit joint option, new in 7.0.0. It is honored only when {{memStub}} is 
> also {{Boolean.TRUE}}. A missing target directory does not turn it on.
> * With both options set, {{JavaAwareCompilationUnit}} and the default javac 
> compiler finish a mixed Groovy and Java compile with no {{stubDir}} and no 
> filesystem target directory. The class bytes are published on the compilation 
> class loader. Resolution reads that loader, in the order described under 
> "What callers should expect".
> * {{groovyc}} and the Ant task leave the option unset, so disk {{stubDir}} 
> and target-directory output remain the default.
> * The joint-compilation section of the groovyc guide documents {{memStub}} 
> and {{memClassOutput}}.
> * Callers enable this through {{CompilerConfiguration}} and 
> {{JavaAwareCompilationUnit}}. The file manager that stores the bytes is 
> package-private, in {{org.codehaus.groovy.tools.javac}}.
> * Tests show a Groovy and Java cycle with no stub directory and no 
> class-output directory, a javac type error on that path, and the unchanged 
> disk path.
> h2. Non-Goals
> * groovy-core does not gain an MCP server, a JSON-RPC API, or an MCP library, 
> and it does not change the LSP protocol.
> * {{groovy-lsp}} and {{groovy-mcp}} stay as they are. {{groovy-lsp}} still 
> uses its own Java compiler and an owner-only temporary directory. Only 
> {{JavacJavaCompiler}} implements {{memClassOutput}}, so using the option 
> there is separate work.
> * This issue does not add an overlay filesystem or a multi-tenant sandbox.
> * Dynamic Groovy is not switched over to static type checking.
> * Builds that leave the option unset keep disk {{stubDir}} and 
> target-directory output. The system property {{groovy.mem.stub}} enables 
> in-memory stubs only.
> * GEP-21 stub generation, including {{MemJavaFileObject}}, stays as it is. 
> Signature changes that must be visible to javac still come from the GEP-21 
> {{Phases.CONVERSION}} stubbers. Other AST transforms are not moved ahead of 
> stub emission.
> h2. Enabling the option
> {{memClassOutput}} ({{CompilerConfiguration.MEM_CLASS_OUTPUT}}) is new in 
> 7.0.0. {{CompilerConfiguration.isMemClassOutput()}} is true only when 
> {{memStub}} ({{CompilerConfiguration.MEM_STUB}}) and {{memClassOutput}} are 
> both {{Boolean.TRUE}}.
> {code:java}
> CompilerConfiguration config = new CompilerConfiguration();
> Map<String, Object> options = new HashMap<>();
> options.put(CompilerConfiguration.MEM_STUB, Boolean.TRUE);
> options.put(CompilerConfiguration.MEM_CLASS_OUTPUT, Boolean.TRUE);
> config.setJointCompilationOptions(options);
> {code}
> * {{memClassOutput}} without {{memStub}} fails the compile with 
> {{memClassOutput requires memStub}}. The system property {{groovy.mem.stub}} 
> enables {{memStub}} only.
> * Only {{JavacJavaCompiler}} implements the option. Any other 
> {{JavaCompiler}} fails the compile with {{memClassOutput requires the default 
> javac joint compiler}}. Using that javac implementation with a plain 
> {{CompilationUnit}} fails the compile with {{memClassOutput requires 
> JavaAwareCompilationUnit}}.
> * When both options are set, {{stubDir}} is not required. The compiler does 
> not add {{-d}}. If the joint options still pass {{-d}}, the file manager 
> consumes it and keeps the class files in memory. {{targetDirectory}} is not 
> added to the compilation class loader, because an earlier classpath entry 
> would hide those classes.
> h2. How classes are published
> {{JavaAwareCompilationUnit}} captures javac {{CLASS_OUTPUT}} with 
> {{InMemoryJavaFileManager}}, in package {{org.codehaus.groovy.tools.javac}}, 
> when javac runs. It writes the Groovy class files from the same compile into 
> that same map during output. Classpath and source input still come from the 
> standard file manager. The manager does no network I/O. The file manager and 
> the classpath store are package-private; callers enable the behavior with the 
> joint option above.
> One URL attaches the map to the compilation {{GroovyClassLoader}}:
> * The protocol is {{x-groovy-mem}} and the host is empty, so hashing or 
> comparing the {{URL}} does not look up a DNS name. On the Java 17 baseline a 
> security manager can still require {{NetPermission("specifyStreamHandler")}} 
> to install the handler.
> * The protocol is not registered with the JVM. Only URLs created for this 
> classpath can be opened. A path that escapes the map is rejected. A plus sign 
> in a resource name stays a plus sign.
> * The URL is appended to the loader. {{URLClassLoader}} cannot remove a URL, 
> so another {{JavaAwareCompilationUnit}} on the same loader reuses the store. 
> {{groovyc}} and the Ant task build one unit per run.
> The unit opens one stage on that store. Lookup prefers the stage and 
> otherwise returns the last committed bytes. A class written during this 
> compile is visible to later phases. A class this compile has not written is 
> still read from the previous commit, when one exists.
> The stage is committed when {{compile}} returns normally after class output 
> has completed. Commit adds and replaces entries and leaves every other name 
> as it was. A failed compile discards the stage, and the previously committed 
> classes stay in place.
> A compile that stops at semantic analysis leaves the stage open. Javac has 
> already run by then. A later {{compile}} on the same unit reuses the stage 
> and does not start javac again. A different unit cannot publish while that 
> stage is open: its {{compile}} throws {{IllegalStateException}} with the 
> message {{another compilation is publishing to this class loader}}.
> h2. What callers should expect
> * A later successful compile replaces the stored bytes of each class it 
> writes. {{loadClass}} returns the class the loader has already defined. A 
> fresh loader is required to run the new bytes.
> * Lookup searches the parent loader first, then URLs in insertion order. The 
> in-memory URL is last. A parent loader or an earlier classpath entry is what 
> resolution and {{getResource}} see. Commit does not change that order, so the 
> earlier entry still hides the bytes.
> * The compile records a warning at {{WarningMessage.LIKELY_ERRORS}}, which 
> the default warning level includes. The warning text contains {{hidden by}}. 
> Type checking uses the visible class. The hidden bytes are committed only 
> when that compile succeeds. A failure discards the stage.
> * Class files that javac produces for the Groovy stubs stay inside javac and 
> are not published. The stub is an input to javac.
> * Annotation processing is turned off with {{-proc:none}} unless the joint 
> options request {{processor}}, {{processorpath}}, {{processor-module-path}}, 
> {{proc}}, or a flag whose name starts with {{proc:}}. Generated Java sources 
> ({{SOURCE_OUTPUT}}) and non-class {{CLASS_OUTPUT}} resources stay in memory. 
> Module-oriented file-manager locations are not supported.
> * {{import module}} skips loader URLs whose protocol is not {{file}}. The 
> groovysh package scan ignores a URL that is neither a file nor a jar, instead 
> of failing the listing. The console classpath dialog lists {{file}} URLs 
> only. The in-memory URL is left out of all three.
> * The decompiler caches class stubs for {{file}}, {{jar}}, and {{jrt}} URLs 
> only. The in-memory URL keeps a stable identity while its bytes can change, 
> so those bytes are read again on the next lookup.
> h2. Tests
> {{MemClassOutputTest}} and {{InMemoryJavaFileManagerTest}} cover:
> * a Groovy and Java cycle with no stub directory and no class-output 
> directory, including a type error reported from javac
> * disk {{stubDir}} with the option off, and {{memStub}} alone still writing 
> the target directory
> * {{memClassOutput}} without {{memStub}}, a joint compiler other than javac, 
> and javac invoked on a plain {{CompilationUnit}}
> * a second unit on the same loader, a unit opened while a stage is still 
> open, and a failed recompile that keeps the last committed bytes
> * a compile stopped at semantic analysis and then finished on the same unit, 
> classes a later compile does not write again, and stub class files left 
> unpublished
> * {{import module}}, a shadowed classpath entry, and a class the loader has 
> already defined
> * a plus sign in a resource name, a path that escapes the map, and generated 
> Java sources kept in memory



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to