Closed xenoterracide closed 1 month ago
The exception report is pretty clear isn't it?
Description:
The bean 'userRepository', defined in com.xenoterracide.security.user.UserRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in com.xenoterracide.security.user.UserRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
at org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter.report(LoggingFailureAnalysisReporter.java:40)
I cannot speak to that arrangement as it's user code. That said, to run the module verification, you don't need to bootstrap the application. I.e., the test case here doesn't need neither @SpringBootTest
nor @ApplicationModuleTest
either as is or in the more complex configuration setup you show.
What I am suspecting though is that your customized module setup is breaking the customizations we make to the component scanning. You have a module located at the root package, and one located in a sub-package of that. As each of the modules' base packages is added to the component scanning, adding com.acme
and com.acme.foo
will get foo
scanned twice. That said, that misconfiguration is nothing the core container is aware of, so it can't detect the original cause of the problem.
right com.xenoterracide.security.user.UserRepository
is the only userRepository
... I've left it to be "auto-registered" without any changes to auto-configuration. I don't know why it's trying to register it again. This doesn't make sense to me, why the results are different from a normal @SpringBootTest
. The suggested remedy doesn't feel like the correct answer as I'm not trying to redefine a bean.
That said, to run the module verification, you don't need to bootstrap the application.
good to know.
What I am suspecting though is that your customized module setup is breaking the customizations we make to the component scanning. You have a module located at the root package, and one located in a sub-package of that. As each of the modules' base packages is added to the component scanning, adding com.acme and com.acme.foo will get foo scanned twice. That said, that misconfiguration is nothing the core container is aware of, so it can't detect the original cause of the problem.
possible. I'm doing spring.modulith.detection-strategy = explicitly-annotated
at the time of this test, even then I'm not certain my setup is as explicit really supports.
Perhaps you can offer a recommendation to my structure. It's possible modulith simply won't work.
The goal is roughly 3 (horizontal) layers, infrastructure, domain, controller, with feature (vertical) slicing. Using packages and jpms to limit access to code. I'm equating my JPMS to be a real module as far as DDD is concerned. This particular repository is for me to develop this theory and use it for highly generic components such as security based models.
my current thought for the domain layer is myorg.<domain bounded context/module>.<aggregate>
previously I had thought myorg.<domain bounded context/module>.model
but then it occurred to me the additional model
wasn't a part of my domain and didn't seem useful. DDD often suggests not including things that aren't part of your domain. I suspect this is more compatible with what you have
From a compile time standpoint myorg.<domain bounded context/module>.model.<aggreate>
might be useful as it prevents different aggregates from referencing each others package level internals.
At the controller layer I was simply going to use myorg.<domain bounded context/module>.controller
this of course sits in a separate jar. In some cases I question the necessity of even breaking this up by the bounded context since each controller really should be self isolating.
There's also the problem that this isn't even a real application, it's just library implementations for whatever applications I decide to create. So then there's perhaps the concerning effect of myorg.security
but what happens when I need myorg.<myapp>.<something>
where something might even be security. Perhaps <myorg>.commons.<context/module>.model.<aggregate>
is what I should have.
Oh, and Application
doesn't actually depend on anything. Before I added security as a shared module, nothing was picked up on it because it just lives at the org root.
Thoughts?
The root of the problem in your example above is that, for some reason, the package containing the application class also contains the other, related modules. Spring's component scanning can only work for package trees. You essentially get your nested package scanned twice, and thus the repository detected twice. Avoiding getting the root package considered an application module base package should solve the problem.
Avoiding getting the root package considered an application module base package should solve the problem.
How does one do that? In spring boot the Application
class is supposed to be at your root, right? and in your examples you're supposed to put @Modulith
on said Application
class, right?
src/main/java
├─ example
| └─ Application.java
├─ example.inventory
| ├─ InventoryManagement.java
| └─ SomethingInventoryInternal.java
├─ example.order
| └─ OrderManagement.java
└─ example.order.internal
└─ SomethingOrderInternal.java
at the very bottom you have (btw, you might want to rename this class to simply be Application
instead of MyApplication
to avoid confusion, although now I see it calls DemoApplication
which is extra confusing as then this class doesn't compile)
package example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.modulith.Modulithic;
@Modulithic
@SpringBootApplication
class MyApplication {
public static void main(String... args) {
SpringApplication.run(DemoApplication.class, args);
}
}
from what I'm seeing, at least from the perspective of the Application
class, it lives at the root as the example shows. If I don't add the shared module
@Modulith(sharedModules = "security")
Then security isn't printed at all, like it doesn't exist, as Application
technically depends on nothing. Honestly reading this It's not even clear how the dependencies are supposed to be declared outside of "magic".
I can – just as at the other tickets you filed – only reiterate that this is a bug tracker, not a personal consulting forum. So this will be my last reply regarding your setup questions:
You're right describing the example arrangements we provide (not surprising). Your arrangement differs from that, as it lists the package your application class resides in as a module in the log output (the very first few lines). I assume this is due to your customized module detection setup, which I don't know anything about. I don't know what security
relates to in the context of you describing our defaults, nor what "outside 'magic'" is supposed to mean.
It feels as if you get lost in customizing and tweaking tons of things at the same time and all those customizations and specialties of your set up contributing some aspect to failure that you have a hard time describing coherently. The architecture verification test does not require an integration test setup in the first place. So this works as designed. As for your application module integration test, I suggest to simplify the arrangement to get to the gist of the issue.
DDD tackling complexity in the heart of the domain, of course it is hard to articulate in twitter sized bites. Anything with any complexity and moving parts requires lots of explanation
I don't know what security relates to in the context of you describing our defaults,
it doesn't, please review the logs and it probably becomes clear.
You constantly criticize me. However I'm running off your documentation that as I just pointed out has code that doesn't compile. In jmolecules there's references to entire books worth documentation using terms that don't even exist in the book. I'm imperfect but pot kettle much.
I'll leave you alone.
I don't know what security relates to in the context of you describing our defaults,
As I said (and included in my code), the only thing I customized was that I made it "explicit" there is no further customization. I included that in the code that I shared in the comments.
So my
@SpringBootTest
with an emptycontextLoads
, runs without error, but my modulith test is failing with some spring data jpa issues, but the root cause isn't obvious to me as I'm just using the basic spring-data-jpa autoconfiguration that loads from spring-boot.modulith work lives in this branch https://github.com/xenoterracide/spring-app-commons/tree/refactor/modulith