Sealed classes for classes in different packages
Asked Answered
D

2

12

If I declare following sealed hierarchy

package a;

import b.B;

public sealed interface A permits B {

}
package b;

import a.A;

public record B() implements A {

}

without using modules (no module-info.java) and try to compile it with Maven I get

[ERROR] .../src/main/java/a/A.java:[5,35] class a.A in unnamed module cannot extend a sealed class in a different package

I'm aware of https://openjdk.java.net/jeps/409 and this section:

The classes specified by permits must be located near the superclass: either in the same module (if the superclass is in a named module) or in the same package (if the superclass is in the unnamed module).

However, shouldn't Maven by default use classpath while compiling? Can this limitation be avoided at all?

If not, doesn't this set a precedent where a feature on module path is more flexible than on class path and that in turn - while classpath is still supported, it's not as first class citizen as it used to be when compared to module path?

Dextrose answered 23/7, 2021 at 8:26 Comment(0)
I
26

The classpath is the unnamed module.

The motivation is that a sealed class and its (direct) subclasses are tightly coupled, since they must be compiled and maintained together. In a modular world, this means "same module"; in a non-modular world, the best approximation for this is "same package".

So yes, if you use modules, you get some additional flexibility, because of the safety boundaries modules give you.

Ivers answered 23/7, 2021 at 14:58 Comment(3)
So in essence, after Java 9 it isn't possible to compile something without using the modules? This was the main detail I wasn't sure about.Decapod
@Ipandzic No, that's not right. Sealed classes work just fine without modules; it just means the boundary of co-maintenance is the package. If you work with modules, you get more latitude, the boundary is all the packages in that module. You can think of this as a positive interaction; you can use sealing without modules, or modules without sealing, or both at once, and if you use them together, you get some bonus flexibility.Ivers
Besides: you can't really work "without modules" in Java 9 and later. The closest you can come is to stuff a bunch of stuff into the unnamed module (i.e. the classpath). While that's pretty close, it's not exactly the same as disabling modules entirely. For example the classes of the JDK itself will still be in modules.Phallus
D
1

Years passed and I forgot to add what I decided to do in my environment with Maven and a Spring application.

I added following new Maven module in parent pom.xml:

<module>my-service-sealed-hierarchy</module>

In my specific instance it contained the following:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
</dependency>

<dependency>
    <groupId>com.infobip</groupId>
    <artifactId>infobip-spring-data-jdbc-querydsl-boot-starter</artifactId>
</dependency>

In <project-root>/my-service-sealed-hierarchy/src/main/java/module-info.java (IDE can help with this part):

module my.service.sealed.hierarchy {
    requires static java.compiler;
    requires spring.data.commons;
    requires com.querydsl.core;
    requires com.querydsl.sql;
    requires java.sql;
}

I put only the sealed hierarchy code into this Maven module. Other Maven modules can now remain unmodularized from JVM perpsective but still leverage the modularized code benefits.

And that was basically it in my case and Maven and IDE (IDEA) no longer complained about having parts of the sealed hierarchy in different packages.

I believe this to be the pragmatic choice if one wants to leverage sealed hierarchy benefits without having bloated packages.

Dextrose answered 25/7, 2024 at 8:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.