Spring `RestController` from `AbstractController` in TeamCity - java

The TeamCity plugin API allows adding controllers by extending their BaseController, which is a thin wrapper around Spring's AbstractController.
When I extend BaseController I can inject beans into the constructor in usual Spring manner. This is managed by a beans definition file like standard spring.,
To provide a Controller I must extend BaseController, override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response), and add the controller to the beans definition. I register a URL route as part of constructor initialisation.
That's about all the extension points available to me for Controller.
I was hoping to be able to write small framework that would allow me to annotate my classes with #RestController and #RequestMapping, etc.
What I think I need to do is:
Wire up an annotation processor to find my controllers and their methods.
Build some sort of mapper which maps #RequestMapping annotated methods to routes
Wire up some content handlers, eg serialising/unserialising for JSON and XML
Dispatch incoming requests to the appropriate method inside my handleRequest method
Most of the above has already been written in Spring and Jersey, and I am wondering where I start researching that.
What classes provide the above functionality?
I've tried a few things to try and instantiate MVC, but it seems to break when ApplicationContext is not available.

Not a TeamCity user. However I'll give my two cents, hoping for the best.
Being that you can register Spring Bean(s), why not trying out ClassPathBeanDefinitionScanner?
If you have access somehow to a Spring lifecycle hook, an initialization one, or if you are able to register a Configuration class, you can create a Bean of type BeanFactoryPostProcessor. I'll give you a Java example, but you should be able to translate it to XML pretty quickly.
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor(final ApplicationContext applicationContext) {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.setResourceLoader(applicationContext);
scanner.scan("your.base.package");
} catch (final Exception e) {
// Handle
}
}
}
};
}
The ClassPathBeanDefinitionScanner will register all classes with Spring stereotype annotations.
You can also make a class implement the BeanFactoryPostProcessor interface directly.

Related

Spring Boot | Using a separate file for logic

I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure

How to integrate between a Spring #Service and a non Spring object?

I have some #Service FooService which on request, makes an API call to some external service and returns some FooResult.
In my project I defined some FooTask. This is actually a wrapper of a java.util.Function (and it being used in some CompletableFuture chain)
Ideally, I'd like the task to call FooService.request(). One solution could be injecting the FooService in the constructor but I'm not sure that's a good idea.
What is the Spring way to do that?
I don't think using FooTask as a Spring Component(a class which is annotated with #Component annotation) causes any problem if your FooTask is a Functional Wrapper and does not save any state, However if your FooTask maintain some state or you want to create multiple instances of that somewhere in your application you can create instances of FooTask outside Spring framework and autowire FooService in it, this is exactly possible using AutowiredCapableBeanFactory but don't go for this approach unless it is necessary:
Do it this way to autowire your FooService in FooTask:
private #Autowired
AutowireCapableBeanFactory beanFactory;
public void doSomething() {
FooTask fooTask = new FooTask();
beanFactory.autowireBean(fooTask);
// obj will now have its dependencies autowired.
}

Spring selectively use implementation instead of interface

Can't find a definitive answer so asking here - Is it possible to turn on CGLIB proxying for only one bean? The scenario is following - I have a class which is autowired and don't implement any interfaces, now I want to add an interface which would cover a small subset of it methods. Is it possible to keep proxying only this class using CGLIB w/o impacting Spring's default behavior (JDK dynamic proxies are preferred)?
I'm using java-based configuration.
There (currently) is not any support out-of-the-box to enable class based proxies for a single class. Instead you would have to create the proxy yourself. The drawback of this is that you would need some intimate knowledge on how Spring works (which I happen to have :) ).
You should/could use the ProxyFactory or ProxyFactoryBean to create a class based proxy for your given class. Your #Bean method would return the proxy instead of the actual class. Spring is then clever enough (at least it should) to detect that it already is proxy and instead of proxying it again it should add the advices to the already created proxy. To make this work without destroying auto wiring and all other nice things Spring gives you, you probably want to create a specific BeanPostProcessor that handles this.
public YourBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof YourBean) {
ProxyFactory factory = new ProxyFactory(bean);
factory.setProxyTargetClass(true);
return factory.getProxy();
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Register this as a bean as you normally would do with a BeanPostProcessor.
#Bean
public static YourBeanPostProcessor yourBeanPostProcessor() {
return new YourBeanPostProcessor();
}
Now you have a pre-created class-based proxy which should be detected and used by Spring.

spring autowiring with processInjectionBasedOnCurrentContext(this);

I have following situation. There is POJO which has autowired implementation of an interface, using some spring magic as shown bellow. However this dependency doesn't get resolved if creation of channels is managed via spring bean. It only works if POJO factory creates channels. Example bellow.
#Controller
public class Test{
#RequestMapping(value = "/load", method = RequestMethod.GET)
public #ResponseBody String testConfiguration() {
// this is pojo and here it works, channels within have wired interface implementation
StaticFactory.getChannels(null);
// if i call same method within spring managed bean (#Service)
// then it doesnt work
System.out.println("channels created");
return "alive";
}
}
Created Channels are POJO but they have autowired interface implementation, which should be enabled with the following in constructor:
public DummyChannel() {
// enables dependency injection of spring managed beans into POJO
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public class StaticFactory {
public static List<SmppChannel> getChannels(Map<ChannelMode, Integer> channelsDefinition) {
List<SmppChannel> dummyChannels = new ArrayList<>();
DummyChannel d = new DummyChannel();
System.out.println("here");
dummyChannels.add(new DummyChannel());
return dummyChannels;
}
}
Now, this thing works if i have non-spring managed Factory. Regardless if mentioned factory is static or not when it creates channels, they have properly wired interface implementation.
However, if i copy paste exactly same code form the factory into Spring managed Bean annotated with #Service, wired dependency is null in created channel.
Could somebody tell me what am i missing here, why things get injected when the factory of channels is not managed by the Spring ?
Edit Solution: // Okay, so the problem is in the fact that DummyChannels enable autowiring support in constructor while Spring beans are still not loaded. It is working if i do this within method that should access autowired service rather then the constructor of DummyChannel.
Have you enabled annotation-config and component-scan in your xml or java configuration? Is the class that you want to inject annotated with #Service or #Resource?
Are you building a Web Service with JAX-WS? If yes, then I think your class (the one doing the autowiring) must implement SpringBeanAutowiringSupport so that Spring's IoC container can handle the injection.

AnnotationConfigApplicationContext has not been refreshed yet

I am developing a spring MVC application. When I try to use AnnotationConfigApplicationContext in my controller class I am getting the following error. I have no idea what this statement exactly means.
#RequestMapping(value = "/generate", method = RequestMethod.POST)
public ModelAndView generateMappingFile(#ModelAttribute Mapping mapping)
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
}
Error Message -->
java.lang.IllegalStateException:org.springframework.context.annotation.AnnotationConfigApplicationContext#116b3c0 has not been refreshed yet
Can someone explain me what went wrong here ? I am using Spring 4.0.1.. I am new to spring mvc.
When you are creating a new instance of an ApplicationContext (regardless which type) you are basically creating new instances of each and every bean configured in that ApplicationContext. That is nice the first time, it might work the second and depending on the amount of beans, the type of beans will crash after that. As the context will never be destroy (until the app crashed and is restarted) you will run into possible memory issues, performance issues, strange transactional problems etc.
A general rule of thumb is to never construct a new instance of an ApplicationContext but to use dependency injection instead.
If you really want access to the ApplicationContext put a field of that type in your controller and put #Autowired on it.
#Controller
public class MyController {
#Autowired
private ApplicationContext ctx;
….
}
Then you can do a lookup for the bean you need in the method. This can be handy if you use the ApplicationContext as a factory for your beans. If all the beans you need are singletons it is better to simply inject the bean you need.
#Controller
public class MyController {
#Autowired
private MappingFileGenerator mfg ;
….
}
Now Spring will inject the MappingFileGenerator and it is available for use in your methods. No need to create a new instance of an ApplicationContext.
More information is in the Spring Reference Guide.
#M.Deinum's comment will get quite a few more upvotes.
Think of creating a new ApplicationContext as instantiating a new (instance of an) application. Do you want to do that every time this (or any other method in said application) is called? No, you don't.
I'm guessing you think you do because you need access to your ApplicationContext in this method. To do that - i.e. to get access to the running application context (rather than creating a new one), you want to do
#Controller // or #Service / #Component / ... : tells Spring that this is a bean, and to inject the specified dependencies
class YourClass {
#Autowired // tells Spring that this object is a dependency should should be injected
ApplicationContext ctx;
#RequestMapping(value = "/generate", method = RequestMethod.POST)
public ModelAndView generateMappingFile(#ModelAttribute Mapping mapping) {
MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
}
The key here is the Autowired annotation, which tells Spring to inject the annotated object as a dependency.
I highly suggest following the links I've included (for starters), as what you're doing here suggests pretty strongly that you haven't wrapped your head around what DI is and does for you, and until you do, using it is likely to be counterproductive toward it's own ends for you.
In case it helps someone, i was having this issue on a new URL Mapping added to a gradle project, i was missing the first slash of the url and that causing this "illegalstate not refreshed yet" on my tests

Categories

Resources