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

Evaluate Spring Modulith actuators #953

Closed
odrotbohm opened this issue Jan 12, 2023 · 13 comments
Closed

Evaluate Spring Modulith actuators #953

odrotbohm opened this issue Jan 12, 2023 · 13 comments

Comments

@odrotbohm
Copy link
Member

Spring Modulith exposes actuators that describe the logical application modules defined in a Spring Boot application. Those modules declare a base package within which all its components reside.

It would be nice if the actuator integration in STS made use of that information to augment the views it provides in supported IDEs to group the listed information by application module. Here are some ideas:

  • The beans view in STS could group the bean nodes by module (fully-qualified bean class name starts with the application module's base package)
  • The same for request mappings for controllers found
  • The "General" tab (Eclipse) could list the modules detected, and a click could jump to its base package

The JSON structure exposed by the actuator is described in the corresponding section of the reference documentation. An example application is available in Spring Modulith's repository. It's spring-modulith-example that can be imported in any IDE, started with ./mvnw spring-boot:run and exposes two modules order and inventory at http://localhost:8080/actuator/applicationmodules.

Please let me know if there's anything else you'd like to know, or I could help with.

@martinlippert
Copy link
Member

Thanks @odrotbohm for filling this enhancement request, would be awesome to support the spring-modulith module structure and the new architecture in the various visualizations for Spring elements that we have in the IDEs. And I think it would be great to not only have this being used in the STS UI, but also VSCode.

Using the actuator information here - as you describes - focuses this on the live information that the IDE grabs from a running Spring application. What do you think about having information at hand without running the app as well? (just as an additional thought)

@odrotbohm
Copy link
Member Author

You're right. The arrangement isn't likely to change much at runtime, and we could also create this JSON structure statically. IIRC we discussed something like this at some point, and you suggested a simple class with a main(…) method accepting a Java package name as argument. What way would you like to consume the JSON then? A file written? The JSON written to stdout?

@odrotbohm
Copy link
Member Author

The fix for spring-projects/spring-modulith#119 contains a class org.springframework.modulith.core.util.ApplicationModuleExporter that exposes a main method working as described above: takes a Java package name and writes the JSON to standard out. If you rather prefer a file, please let me know. Code is available via the 0.3 snapshots.

@martinlippert martinlippert added this to the Backlog milestone Feb 24, 2023
@BoykoAlex BoykoAlex modified the milestones: Backlog, 4.18.1.RELEASE Apr 20, 2023
@BoykoAlex
Copy link
Contributor

@odrotbohm we marked it for the next release only as a marker rather than deadline. Something we'll start looking at in the next 2 weeks.

@odrotbohm
Copy link
Member Author

That's great news, thanks! Let me know if I can be of any help.

@BoykoAlex
Copy link
Contributor

I have glanced through the Modulith docs. I think we can show something in the live hints for this... Which module a bean is coming from for example...
I think though most useful would be if we show errors in the IDE for imports (or type usages in the code if we want that as well) that are illegal with respect to module structure. I wonder if JSON module tree (i suppose the same that is exposed in the actuators) could be generated at build time similar to boot properties metadata json generated by annotation processor.
I think we could watch changes to that json file (similar to properties metadata) and reload the module tree for a project. Hopefully the module tree then could find a module for a package name and determine if module X is a dependency of module Y. Then i think we could scan the imports of an AST and determine if any of the imports break the module integrity.
We could also perhaps show a codelense at the top about the current module and a list of module dependencies perhaps, navigate to module definition, i.e. package-info.java file etc. However, i think these are secondary UI improvements.
(cc: @martinlippert @odrotbohm )

@BoykoAlex
Copy link
Contributor

BoykoAlex commented May 12, 2023

We could also implement a command showing the module dependency tree if we want... Show some s3 tree for example... but I'd try to show it even for the code that is not running.
It'd be most logical to show some extra data in the package/project explorer in the IDE, but LSP doesn't seem to be of any help annotating project tree widget...

@BoykoAlex
Copy link
Contributor

@odrotbohm Just noticed that there is java app generating the json... perhaps i could start trying that for now. I'm very curious to know about what you think about the same approach as for boot properties metadata JSON...

@odrotbohm
Copy link
Member Author

Thanks for your feedback, Alex. @martinlippert and I had agreed on the main method approach for a start, as the module structure metadata creation takes a few milliseconds (as it needs to analyze the application's class files and potentially ones from JARs). Thus, a manual trigger to update the information seemed reasonable, also, as the structure is unlikely to change regularly.

For the dependencies check, I wonder if we can somehow rather leverage the Java APIs already in place on ApplicationModules to verify the arrangement. Given a source type and a target one, we should be able to look up the ApplicationModule for each of them (via the fully qualified class name), and – in case they are not the same – check targetModule.isExposed(target). Details aside, reusing the API would allow us to prevent having to replicate the access rules. We could also turn it around and add more details to the violations report we'd generate for verification requests so that we can potentially return a list of invalid source-target combinations. That might make it easier for you to add the markers, e.g. "In every source source file, mark all type references to targets as invalid" without having to examine every reference whether it's valid or not.

Happy to jump on a Zoom to discuss.

@BoykoAlex
Copy link
Contributor

BoykoAlex commented Jun 29, 2023

@odrotbohm I'm a bit confused how to build the ApplicationModules... I seem to only have one option: build it using the root package... The root package seem to be the one containing the spring app class... Is this correct? Otherwise, how can I determine the root package?

Wonder if for class B imported into class A the following would work:

  1. Determine package for class A, suppose it is x.y.z.
  2. Compute ApplicationModules for x.y - get the ApplicationModule for A call it moduleA
  3. Compute the same for class B. Thus moduleB is computed.
  4. Then moduleA.isExposed(moduleB.getType(classBFQName).get())

@odrotbohm
Copy link
Member Author

odrotbohm commented Jun 29, 2023

Can you elaborate what you're trying to achieve? ApplicationModules is primarily designed to be used with the Boot application class in particular. The overload of ….of(…) taking a package string primarily exists for testing purposes.

I'm not certain that I follow on the class A / B thing, either. It doesn't really make sense for a type in one module to be exposed by another, as – by definition – a type can only live in one module. If it's about implementing the dependency checks described above, the algorithm could be as follows:

  1. Find the Spring Boot application class within the project (something annotated with @SpringBootApplication within src/main/java), create an ApplicationModules instance for that and keep it around.

then:

  1. Given a type (e.g. one, open in an editor)…
  2. Collect all outgoing type references. For each…
  3. call modules.getModuleByType(referencedType) -> on empty Optional, ignore
  4. if present, call ….isExposed(…) on the ApplicationModule. true -> all good, false -> reference invalid.

Does this make sense? If you'd like to void working with Class objects, I think I'd need to add an overload to isExposed(…) but I could certainly do that.

HTH

@BoykoAlex
Copy link
Contributor

Yes, it helps, thanks very much

@BoykoAlex
Copy link
Contributor

Initial Modulith Integration, namely the described above validation markers, have been implemented. Last commit adds some performance enhancements and manual metadata refresh 6496537

The highlighting of exposed classes in PE in Eclipse/VSCode is tracked here: #1070

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants