[
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)