How to add rest controller to spring boot library, and use it in another application? - spring-boot

I am working on a library xyz.jar that needs to add a UI page with mappings like this one:
#RestController
public class LibCtrl {
#EventListener(ApplicationReadyEvent.class)
#RequestMapping("/updateDomainList")
String updateDomainList() {
return "we can call a controller from another jar like this";
}
}
This then needs to be called in my main springboot application, myMainApplication.war, so when I call
http://localhost/myMainApplication/updateDomainList
I should see
we can call controller from another jar like this
on the browser.
How can achieve this? #Component also did not work for me. Once it begins to work, would #Autowired to JdbcTemplate also work?

It was a simple fix. #ComponentScan allows for multiple packages to be scanned. This made is possible for me to add my Library Packages to be managed by Spring. Just add the following to your application class.
#ComponentScan({"my.mainapplication.package","my.library.package"})

Related

Spring Boot 404 Error with Simple Controller

I am trying to make a simple Spring Boot Application with the simple controller (Restful controller) where the function is returning the String that is to be printed on the Web page. But I am facing a problem where I am getting 404 error every time. In my views, I am setting up the application right. I have just used spring-boot-starter-web as the dependency.
Application file:
Any help would be appreciated.
And I know #SpringBootApplication automatically take all the annotation.
Either your controller class needs to be in or sub package of SpringBoot Application class or the package in which controller class exists needs to be scanned explicitly using #ComponentScan to resolve this
Can you show me the structure of your project?, I believe the problem Spring is not finding your userController, #SpringBooApplication use the #ComponentScan how is in charge to search for all the spring annotations un your code, so I believe is something
Need to add #ComponenScan the resquest to http:localhost:8080/api should return "Hello" if you need to add a path http:localhost:8080/user/api do as follow:
#RestController
#RequestMapping(value = "/user")

Spring Boot, Maven, disable specific RestController in the derived project

In my Maven, Spring Boot 2 project I have Maven module called api1. I have declared a number of #RestControllers there.
In order to extend the logic of the api1 module, I have implemented another Maven module called api2 and placed api1 there as Maven dependency.
Right now all of the #RestControllers from api1 project are initialized in the api2 because all of them are present on the api2 classpath.
How to disable a certain #RestController in api2 project?
You may try using Condition interface from Spring which provide support for conditional enable/disable of the beans based on certain condition/expression.
something like below:
#RestController
#ConditionalOnExpression("${api1.controller.enabled:false}")
#RequestMapping(value = "/", produces = "application/json;charset=UTF-8")
public class Api1Controller {
#RequestMapping(value = "/greeting")
public ResponseEntity<String> greeting() {
return new ResponseEntity<>("Hello world", HttpStatus.OK);
}
}
you have to set the Conditional expression by some way (env. variable / property key). check this for some reference. Condition docs can guide you on more details.
I think the crucial fact here to understand is that Spring works at runtime only, while maven matters in build time.
So maven sees that api2 depends on api1 so it understands that both modules have to be included in the artifact (in the case of spring boot its a big jar with all modules inside).
Now, when spring starts - it "takes for granted" that all modules are accessible, and depending on spring configurations it just defines beans to be loaded and processed, all rest controllers are among these beans of course.
So I assume, you don't mind having two modules in the artifact (and in classpath).
In this case, you shouldn't touch the maven part at all, but when the spring boot application starts it has to be "instructed" somehow that some rest controllers have to be excluded. The point is that it should be done not in terms of modules ("hey, spring, this controller belongs to module api2, so it has to be excluded"), but in terms of business "jargon". For example, api1 contains all "admin" functionality and api2 contains all "applicative" stuff. So, if you work with Java configurations, for example, you can do the following:
Inside module api1:
#Configuration
#ConditionalOnProperty(name = "admin.enabled", havingValue=true)
public class AdminControllersConfiguration {
#Bean
public AdminControllerFromModuleApi1 adminController() {
return new AdminControllerFromModuleApi1();
}
}
}
In module api2 you just define your rest controllers in a similar way but without "#ConditionalOnProperty" annotation.
The thing with this annotation is that it allows to "switch off" beans or entire configurations like in my example.
So, when you start api2, you just define in "application.properties" or something the following:
admin.enabled=false
And your controllers won't be "deployed" by spring although physically the files are certainly in the classpath.
Of course, since spring allows different types of configurations, this method might not be applicable to your project, but the idea is still the same.

Spring in a JavaFX application - how to property handle controller as dependency?

I have a JavaFX application that uses spring boot, exactly as described in this blog post:
http://www.greggbolinger.com/let-spring-be-your-javafx-controller-factory/
I am using the FXML loader overriding the controller factory to use spring.
The problem is that Spring loads the controller class marked as #Component on application start or later if marked with #Lazy, but keeps the bean in memory.
If I open a Stage, modify the data, close the stage and open it again, the data is still there (because the controller was kept by spring). It also gets in the way if I open two of the same Stage (window). It shares the same controller, so if I modify one, the other modifies too, and this is not the desired behavior.
How to I properly handle JavaFX controllers with spring?
Thanks!
Mark the controller as having prototype scope, so that a new instance is created on each request:
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Controller {
// ...
}

How to use Rest service class as a library class

I have a Spring app and I created a Rest service with a couple of GET methods.
Now that web service needs to be moved to a library module to be used by other modules. How can I do that? Where to place it in the project I want to use it? Extend it in the project? I don't have anything to add to it or override (it is a kind of utility web service). I just need its name as a component. Would I just have some child class that is just extending it with empty body and give it a component name? Is that ok?
import xxx.yyy.lib.UtilityWebService;
#Component("utilityWS")
public class MyWebService extends UtilityWebService{
}
What would be the best practice for this situation?

Plugin System in Spring Boot for modular applications

I looking for dynamically loading jar in spring boot after compiling, for example I will put jars in some folder and when spring boot is started, all jars from this folder will be injected into spring boot app. I don't know how can I do this with spring boot, and if You know can help me with this, with some example.
I need this jars to have #Service, #Controller as this will be module (plugin), with adding capabilities to my spring boot app.
Is possible to do this with spring boot, and if it is possible, please provide me with some sample code.
Thanks in advance.
UPDATE:
I found something https://www.youtube.com/watch?v=F-sw2pFdcDw https://code.google.com/p/jspf/
UPDATE 2: I can't get #Controller bean from plugin jar registered in Spring Boot
Have a look at FlexiCore, an open-source framework that brings modularity to spring boot utilizing plugins(jars) loaded at runtime See wizzdi and FlexiCore.
for example FlexiCore allows you to create a project ( compiled into a seperate jar from your main application) that contains a spring bean as follows:
#Component
#Extension
public class HelloWorldService implements ServicePlugin{
public String hello() {
return "Hello World!";
}
}
it will be automatically be loaded once placed inside the designated plugins folder, it basically allows a full support for most(all) of spring boot features , so for example you can add a RestController bean to your jar as well , FlexiCore will automatically load that bean allowing you to call the controller as if it was in your main application jar:
#RestController
#Extension
public class TestEntityController implements Plugin {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#Autowired
private TestEntityService testEntityService;
#PostMapping("/createTestEntity")
public TestEntity createTestEntity(#RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
return testEntityService.createTestEntity(name);
}
#GetMapping("{id}")
public TestEntity getTestEntity(#PathVariable("id")String id) {
return testEntityService.getTestEntity(id);
}
}
Disclaimer: I am the CTO of wizzdi, the company powering FlexiCore.
One option is definitely to just use broad #ComponentScan. If you add new jar to classpath the annotated classes from that jar will get discovered via #ComponentScan, #Controllers will get mapped etc.
The XML equivalent here would be placing xml configuration files somewhere to your classpath (META-INF folder being obvious choice) and import them all using wildcard. The idea is the same. If the plugin jar file is on classpath you will get the xml file imported and the beans (controllers, ...) will get loaded.
There are drawbacks to this approach like the modules not being isolated but its definitely option for simpler applications.
You can find a sample spring boot web project here.
By dynamically loading jars I assume you want to add dependencies to your project. For this you can update pom.xml of the sample project and put your dependencies here.

Resources