Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nested packages for @Modulith(sharedModules) #524

Open
tvogel8570 opened this issue Mar 7, 2024 · 5 comments
Open

Allow nested packages for @Modulith(sharedModules) #524

tvogel8570 opened this issue Mar 7, 2024 · 5 comments
Assignees
Labels
meta: waiting for feedback Waiting for feedback of the original reporter

Comments

@tvogel8570
Copy link

Current Behavior
The sharedModules parameter of the @Modulith annotation does not allow nested packages, even when the nested packages are explicitly listed.
package structure - com.app.core.exception

@Modulith(sharedModules={"com.app.core"}, useFullyQualifiedModuleNames = true) and @Modulith(sharedModules={"com.app.core", "com.app.core.exception"}, useFullyQualifiedModuleNames = true) result in java.lang.IllegalArgumentException: Module com.app.core.exception does not exist!

@Modulith(sharedModules={"com.app.core"}, additionalPackages = { "com.app.core.exception"}, useFullyQualifiedModuleNames = true) results in
Module 'com.app.user' depends on non-exposed type com.app.core.exception.EntityNotFoundException within module 'com.app.core'!

Desired Behavior
Allow for wildcard(1) or explicitly listed(2) sub-packages to be referenced within all modules.
1 @Modulith(sharedModules={"com.app.core.*"}, useFullyQualifiedModuleNames = true)
2 @Modulith(sharedModules={"com.app.core", "com.app.core.exception"}, useFullyQualifiedModuleNames = true)

Workaround
change package structure to com.app.core and com.app.exception with @Modulith(sharedModules={"com.app.core", "com.app.exception"}, useFullyQualifiedModuleNames = true)

@odrotbohm odrotbohm self-assigned this Mar 8, 2024
@odrotbohm odrotbohm added the meta: waiting for feedback Waiting for feedback of the original reporter label Mar 8, 2024
@odrotbohm
Copy link
Member

odrotbohm commented Mar 8, 2024

There simply is no such thing as nested modules, yet. In other words, if a module named com.app.core exists, no module com.app.core.exception can exist at all. Note, that the attribute is sharedModules, not sharedPackages. That the module names look like packages is a side effect of the setting to enable qualified module names.

Can you take a step back and elaborate why you think you'd need to list that nested package in the first place? Shared modules are automatically included in integration test executions and effectively lead to the component scanning to include the package of the shared module. That means that declaring com.app.core a shared module, this will include – and thus bootstrap – code in nested packages such as the ….exception one anyway.

@tvogel8570
Copy link
Author

tvogel8570 commented Mar 9, 2024 via email

@odrotbohm
Copy link
Member

No worries. I am a bit surprised you state that you could get this to work, as the shared modules definition is not even considered during the verification. The Javadoc of the attribute clearly states that it's used to define modules that are supposed to be included in integration test executions (using @ApplicationModuleTest) but it will not change anything about the outcome of a AppplicationModules.of(…).verify().

As documented here, nested packages of application module base packages are considered internal and other modules are not allowed to refer to code within those by default. I.e., it is not surprising that references to those would break the verification. To expose such types to other packages, the package they reside in needs to be declared a named interface.

We generally discourage the use of packages to group types by their stereotype (exceptions, controllers, services etc. getting their own package) as that fundamentally subverts the encapsulation effects of packages. That said, Spring Modulith 1.2 will ship with the notion of an “open module”, which would also expose its externals (in other words: all nested packages) to other modules.

If you find the time, it would be helpful to look at a reproducer as that allows us to find out what we're really talking about here.

@tvogel8570
Copy link
Author

tvogel8570 commented Mar 9, 2024 via email

@pmouawad
Copy link

pmouawad commented Mar 21, 2024

Hello @odrotbohm, Firs thanks for your work on Spring, it's always a great pleasure to work with it. We started using Modulith on a project and it allows us to detect invalid dependencies. But the nested item is not clear for me. Regarding your comment "To expose such types to other packages, the package they reside in needs to be declared a named interface."

You reference this:

The effect of that declaration is twofold: first, code in other application modules is allowed to refer to SomeSpiInterface. Application modules are able to refer to the named interface in explicit dependency declarations. Assume the inventory module was making use of that, it could refer to the above declared named interface like this:
..

I have 2 questions:

  • If you have nested packages, is this expected to work foo::nestedlevel1::nestedlevel2 ? I understand it's not recommended. Maybe the last point should be added or highlighted to documentation, I may have missed it.
  • Regarding "For modules without explicitly described dependencies, both the application module root package and the SPI one are accessible.", it's not clear, do it mean that if another module (not nested) does not declare any AllowedDependencies it would be the foo and all NamedInterface in it ?

Thank you, hoping my questions are not too stupid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta: waiting for feedback Waiting for feedback of the original reporter
Projects
None yet
Development

No branches or pull requests

3 participants