Summary
<property name="postBootCommands"> in arquillian.xml triggers UnsupportedOperationException whenever a command line has at least one argument. The connector parses each command into an immutable list and then mutates it.
Reproduces 100% with ee.omnifish.arquillian:arquillian-glassfish-server-managed:2.1.3 on Eclipse GlassFish 8.0.1 (JDK 21).
Reproducer
arquillian.xml:
<container qualifier="glassfish-managed">
<configuration>
<property name="glassFishHome">/path/to/glassfish8</property>
<property name="domain">domain1</property>
<property name="postBootCommands">
create-system-properties foo=bar
</property>
</configuration>
</container>
Any test that boots this container fails with:
java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:155)
at java.base/java.util.AbstractList.add(AbstractList.java:113)
at ee.omnifish.arquillian.container.glassfish.managed.GlassFishServerControl.executeAdminDomainCommand(GlassFishServerControl.java:315)
at ee.omnifish.arquillian.container.glassfish.managed.GlassFishServerControl.start(GlassFishServerControl.java:162)
It also fires at @AfterSuite teardown when keepServerRunning=false.
Root cause (from disassembly of 2.1.3)
In GlassFishServerControl.start(), the post-boot loop builds a per-command arg list with either Arrays.asList(Arrays.copyOfRange(tokens, 1, end)) (when the command has args) or List.of() (no args). Both are immutable.
That list is then passed to executeAdminDomainCommand(...), whose body does:
// args = parameter #3 (the immutable list above)
if (config.getDomain() != null) {
args.add(config.getDomain()); // ← UnsupportedOperationException
}
executeAdminCommand(..., args, ...);
The contract violation is executeAdminDomainCommand mutating its caller's list. The cleanest fix is for that method to defensively copy:
private void executeAdminDomainCommand(String cmd, String op, List<String> args, ProcessOutputConsumer out)
throws LifecycleException {
List<String> mutable = new ArrayList<>(args);
if (config.getDomain() != null) {
mutable.add(config.getDomain());
}
executeAdminCommand(cmd, op, mutable, List.of(), out);
}
This also fixes the corresponding call from stop() / stopContainer() if those use the same path with an immutable arg list.
Workaround
Until this is fixed, consumers must avoid postBootCommands entirely. Editing domain.xml directly via Maven or asadmin running against an already-started server are the available alternatives.
Versions
- ee.omnifish.arquillian:arquillian-glassfish-server-managed 2.1.3
- Eclipse GlassFish 8.0.1 (JDK21 distribution)
- JDK 21.0.5 (Corretto)
- Maven 3.9.15
- Arquillian core 1.10.0.Final
Summary
<property name="postBootCommands">inarquillian.xmltriggersUnsupportedOperationExceptionwhenever a command line has at least one argument. The connector parses each command into an immutable list and then mutates it.Reproduces 100% with
ee.omnifish.arquillian:arquillian-glassfish-server-managed:2.1.3on Eclipse GlassFish 8.0.1 (JDK 21).Reproducer
arquillian.xml:Any test that boots this container fails with:
It also fires at @AfterSuite teardown when keepServerRunning=false.
Root cause (from disassembly of 2.1.3)
In GlassFishServerControl.start(), the post-boot loop builds a per-command arg list with either Arrays.asList(Arrays.copyOfRange(tokens, 1, end)) (when the command has args) or List.of() (no args). Both are immutable.
That list is then passed to executeAdminDomainCommand(...), whose body does:
The contract violation is executeAdminDomainCommand mutating its caller's list. The cleanest fix is for that method to defensively copy:
This also fixes the corresponding call from stop() / stopContainer() if those use the same path with an immutable arg list.
Workaround
Until this is fixed, consumers must avoid postBootCommands entirely. Editing domain.xml directly via Maven or asadmin running against an already-started server are the available alternatives.
Versions