-
Notifications
You must be signed in to change notification settings - Fork 104
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 architecture annotations to be used on Java modules #128
Comments
Wouldn't it make more sense to annotate the packages exposed by a module, then? |
I'm not entirely sure how some of these annotations are meant to be applied. In this case, my intention is that all packages should be considered part of the A major source of confusion is the The documentation around when and why to use each type of module feels lacking. While I recognize that these are DDD concepts that didn’t originally have annotations, I don’t believe a bounded context was intended to be applied to a package. It’s also unclear if I also doubt that a bounded context ( Interestingly, this could theoretically introduce additional compile-time constraints. For instance, if |
I've been reflecting on how I would adhere to such designs if JPMS modules were permitted. Here's what I'm thinking:
Thus, any @BoundedContext
@DomainLayer
@Module
module tld.myorg.security {...} Examples:/**
* A rough explanation, possibly covering why security is its own domain.
**/
@BoundedContext(name = "Security")
@DomainLayer
@Module
module tld.myorg.security {
exports tld.myorg.security;
exports tld.myorg.security.user;
opens to whatever;
} @Aggregate // Missing concept, possibly for another ticket/issue
// Automatically part of the Domain Layer within the security context/module
package tld.myorg.security.user; @UserInterfaceLayer // Because this could use a rename ;)
@Module
module tld.myorg.security.controller {
// No EXPORT!!! ;) because nothing should import these in a Spring app
opens tld.myorg.security.controller to spring...;
} At this point, I'm uncertain whether the user interface should be scoped to a single bounded context. My hesitation likely stems from the belief that a well-structured monolithic application with proper modules can be split into multiple microservices by creating projects that depend on different "user interface" layers. These modules would then be composed into an application project. I understand not everyone may agree with placing controllers in a separate module or package from the feature slice, but it does help keep business logic out of the controllers. It also makes swapping implementations—such as replacing REST with GraphQL or supporting both—more manageable. P.S
Thus, any @BoundedContext
@DomainLayer
@Module
module tld.myorg.security {...} Examples:/**
* A rough explanation, possibly covering why security is its own domain.
**/
@BoundedContext(name = "Security")
@DomainLayer
@Module
module tld.myorg.security {
exports tld.myorg.security;
exports tld.myorg.security.user;
opens to whatever;
} @Aggregate // Missing concept, possibly for another ticket/issue
// Automatically part of the Domain Layer within the security context/module
package tld.myorg.security.user; @UserInterfaceLayer // Because this could use a rename ;)
@Module
module tld.myorg.security.controller {
// No EXPORT!!! ;) because nothing should import these in a Spring app
opens tld.myorg.security.controller to spring...;
} At this point, I'm uncertain whether the user interface should be scoped to a single bounded context. My hesitation likely stems from the belief that a well-structured monolithic application with proper modules can be split into multiple microservices by creating projects that depend on different "user interface" layers. These modules would then be composed into an application project. I understand not everyone may agree with placing controllers in a separate module or package from the feature slice, but it does help keep business logic out of the controllers. It also makes swapping implementations—such as replacing REST with GraphQL or supporting both—more manageable. P.S. for completeness this is class that I'm not certain if it's infrastructure or domain layer. I lean towards Infrastructure due to the "not for direct use", at the same time more complicated versions of this class could contain business logic for contruction. package com.xenoterracide.security.user;
import jakarta.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;
import org.immutables.builder.Builder;
import org.immutables.value.Value;
import org.jmolecules.architecture.layered.InfrastructureLayer;
import org.jspecify.annotations.NonNull;
/**
* Do not use directly, this class is for generating builders that you should use instead.
*/
@InfrastructureLayer
@Value.Style(newBuilder = "create", jakarta = true, jdk9Collections = true, jdkOnly = true)
final class UserFactory {
private UserFactory() {}
@Builder.Factory
static User user(@NonNull String name, @NonNull Set<IdentityProviderUser> identityProviderUsers) {
return new User(User.UserId.create(), name, new HashSet<>(identityProviderUsers));
}
} |
I appreciate your input, but be reminded that this is a bug tracker, not a discussion forum how to use the annotations. So I deliberately skip the brain dump on modules layers etc. Furthermore, please recognize that JPMS is only rarely used in real-world applications, so it cannot be the center of our design attention. I still think that the currents state of affairs is just fine, because the annotations that make sense on packages can already be used there. They are also already detected in exactly that place by relevant integration technology. What you're suggesting here is being able to use those annotations on The essential question to be answered is what this step would enable that's currently impossible, except "being able to declare the annotation in a different file". If we find an answer to that question, I'm happy to further investigate. In the absence of a proper answer, I'd rather stay with the current state of affairs. |
but it is a place to suggest improving documentation. I'm brain dumping because I don't know how to develop a comprehensive list of annotations that belong on modules; as from much of the documentation it's not clear what the intent is.
I'm not certain I understand. The only step needed, assuming the annotations are for documentation purposes is to allow them to annotate a module. Then a given annotation should be applicable on a @Target({
ElementType.MODULE
}) after that, consumers would also need to look at |
adding, e.g.
@DomainLayer
, to a package is cool, but it would be nice to add that to amodule-info.java
. That would look something like this from a consumer perspective, and should affect all packages inside of the module. I think individual packages should be able to be considered to override this. For example my security package might have an unexported (or not exported to everything) nested package that is for infrastructure, but that's less of concern to people consuming the module because they can't see it anyways.I could look into this, but no promises. It's not hard to let the annotation be on the module, the problem is making tooling recognize it.
The text was updated successfully, but these errors were encountered: