Friday, June 30, 2023

Quiz yourself: Java’s sealed-type mechanism and the module-info.java file


Imagine you are working on a new unit testing framework for Java classes and start with the following folder hierarchy:

src
 └───com
    └───acme
        └───test
              └───Test.java

There’s a single base Java class inside the project.

Core Java, Oracle Java Career, Oracle Java Skills, Oracle Java Jobs, Oracle Java Preparation, Oracle Java Tutorial and Materials, Oracle Java Guides, Oracle Java Certification

package com.acme.test;

// import statement(s) here if any

abstract sealed public class Test permits StaticTest, DynamicTest {
    abstract public void test();
}

Which statements correctly describe the conditions when the code compiles successfully? Choose two.

A. If you put the StaticTest and DynamicTest classes in the com.acme.test package, you do not need to provide module-info.java.

B. If you put the StaticTest and DynamicTest classes in the com.acme.test.util package, you do not need to provide module-info.java.

C. If you provide module-info.java, you must put the StaticTest and DynamicTest classes in the same module with the Test class.

D. If you provide module-info.java, you must put the StaticTest and DynamicTest classes in the com.acme.test package.

E. If all modules have a proper module-info.java file, you may put the StaticTest and DynamicTest classes in different modules.

Answer. This question investigates some key restrictions of the sealed-type mechanism.

The sealed-type mechanism allows source code to make it very clear that only a specific set of subtypes are assignment-compatible with the sealed base type. Of course, it’s always been possible to limit the number of types that are assignment-compatible with a given type simply by not coding more classes than you want. But in that older approach, the design intent is not explicit in the code, and if others who are unfamiliar with your intentions work on the code, they might break this intention and create bugs by mistake.

Another benefit of sealed types is that if a naively made change adds a new assignment-compatible type, it causes a syntax error, alerting the programmer that the change should be discussed with others who are thoroughly familiar with the design.

A third benefit, which is expected to be realized fully when the final version of pattern matching for switch is released, is the ability to alert programmers to other areas of code that need to be updated if new assignment-compatible subtypes are added by the proper syntactic mechanism. (Specifically, the switch statement will be able to issue an error if the new type is omitted from the set of patterns mentioned in case clauses.)

In pursuit of these goals, Java 17’s JEP 409 (sealed classes) makes the following comment:

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

Notice this enumerates two possibilities.

◉ All elements of the sealed-type hierarchy must be in the same module.
◉ If the code that’s compiled and run is not in an explicit module (that is, the code on the classpath is in the unnamed module, which is not explicit), the elements of the hierarchy must be in the same package.

It’s worth noting that the Java compiler determines whether code is intended for use in the module system by determining the presence or absence of a module-info.java file. This is somewhat approximate, since code can be compiled into a module but then be executed from the unnamed module if the JAR file containing the code is located on the classpath during execution.

From the rules listed in JEP 409, you know that it’s mandatory that all elements of the sealed hierarchy be in the same package if the code is not running in a named module. This makes option A correct.

You also know that it’s permissible to place members of the sealed hierarchy in different packages only if the code is running in a named module. Since the compiler approximates this determination based on the presence or absence of a module-info.java file, option B is incorrect.

Option C is also correct because, as mentioned above, permitted types must be as close as possible to sealed types, and the most permissive interpretation is that all the types must be in the same module. One factor here is that modules are commonly developed and compiled independently, which means it’d be much harder to keep track of the total hierarchy if this rule did not exist.

Option D is incorrect. It is not mandatory to put all the permitted types into the same package when you build a sealed-type hierarchy with a module-info.java file, which the compiler interprets as building a module (even if the code might not be run in that way).

Option E is also incorrect, because you can never spread a sealed type and its permitted types across different modules.

Conclusion. The correct answers are options A and C.

Source: oracle.com

Related Posts

0 comments:

Post a Comment