Error in groovy beans - spring

I have this .groovy file
#RestController
class SimpleBeanApp{
#Autowired
String text
#RequestMapping("/")
String index(){
"You can do: ${text}!"
}
beans {
text String, "-Spring Boot with Groovy beans-"
}
}
When i run it I have
file...beans.groovy: 12: unexpected token: beans # line 12, column 2. beans
which is the beans{, I have tried adding an annotation #Bean before beans but it doesn't work.

You are trying to inject a String text with the #Autowired annotation at the beginning of your controller class.
Spring searches beans with type String in its dependency injection scopes. The line that doesn't compile was supposed to provide that missing bean.
I'm not familiar with groovy, but it has to look something like this:
#Bean
String text() {
return "-Spring Boot with Groovy beans-"
}
That's how you create a bean of type String and name text. It will be found by springs dependency injection framework and linked to the #Autowired field at the top of your controller.

what mana sugests is 'Java' construct. It will work, but is not groovy-ish.
Indeed, groovy SHOULD allow you to create beans in a more 'groovy' way; by providing a beans closure.
I was searching to solve the same issue myself today.
Turned out I had to find out by myself... So providing here my 2 cents.
That 'beans' definition is actually a method belonging to a GroovyBeanDefinitionReader
So, you need to create one such class and invoke its 'beans' method providing it a closure will the beans definition, like in the example in the javadoc.
(I love groovy, but from time to time I feel like I need to understand what the code means in a C-programmer fashion to understand what I'm really doing... must be bound to ageing...)
Note you need to get hold of the application context.
One way I found (there could be better ways) is:
class SimpleBeanApp implements ApplicationContextAware {
...
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
def beanConfig = new GroovyBeanDefinitionReader(applicationContext)
beanConfig.beans {
text String, "-Spring Boot with Groovy beans-"
}
}
}
Or, you could also put your beans configuration in a separate groovy script to be loaded while configuring your spring application. Like:
static void main(String[] args) {
SpringApplication.run ([DemoApplication,new ClassPathResource('/DemoConfig.groovy')] as Object[], args)
}
And put within a DemoConfig.groovy file the beans configuration:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
beans {
...
}
Note that DemoConfig.groovy should be located in:
/src/main/resources/DemoConfig.groovy

Related

Spring Boot: scanning components into an injectable list or set

Spring Boot here. I have dozens and dozens of classes that are all subclass/implementations of the same interface:
public interface AnimalService {
void eat();
// etc.
}
#Component
public class DogService implements AnimalService {
#Override
public void eat() { return ... }
// etc.
}
// many many many of these
I have a #Service-annotated class (AnimalService) that needs to be injected with each one of these subclasses:
#Service
public class AnimalProcessingService {
#Autowired
private List<AnimalService> allAnimalServices; // DogService, SharkService, etc.
// the rest of the class definition is omitted intentionally
}
Now I could do this injection the hard way:
#Configuration
public class AnimalConfig {
private DogService dogService;
private SharkService sharkService;
// ...etc.
#Bean
public List<AnimalService> allAnimalServices() {
return Arrays.asList(dogService, sharkService /*, ...etc. */);
}
}
But there's gotta be an easier way to do this, right?
How can inject this List<AnimalService> without having to manually create the list? Does this method allow you to filter out certain candidates (like if I just want a subset of the animal services)? Ideally something annotation-based (even if I have to define my own annotations) that works with Spring autowiring/DI/component scanning. Thanks for any and all help here!
Essentially you're looking for #ComponentScan, which is a Spring (not Boot) annotation. It allows you to define a list of packages for Spring to scan for #Components (or "sub-annotations" such as #Service), to automatically instantiate beans of those classes and add them to the Spring context. So you can consider it a more automated way of the more manual #Bean method declaration.
Since you're using Spring Boot, however, you might want to look into #SpringBootApplication which, when used, enables component scan automatically. All you have to do is making sure your #Component classes are defined in the same package as, or sub-packages of, the #SpringBootApplication-annotated class.
Once you've enabled component scanning, you can just inject a List<AnimalService> where you need it, like in a constructor, and do your processing (filtering?) there.

How to pass a POJO to the SpringBoot application run method?

I have this
#Bean public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
// use a lambda expression to define a CommandLineRunner
return args -> {
... work ...
};
}
which is invoked like this
SpringApplication app = new SpringApplication(MyApp.class);
app.run(args); // perform configuration magic and invoke the above lambda function
This works great as long as the application was only used from the CLI. Now, the application is going through some refactoring to support a new run-time platform, and now I would like to do this:
app.run(complexOject); // pseudo-code, no such method in SpringApplication
i.e. I need to pass an ComplexObject to the application, while still preserving all the magic auto-configuration.
How can this be accomplished? Solutions with the least amount of code change are preferred.
The refactoring steps to enable a CommandLineRunner to receive arbitrary parameters is roughly as follows:
Move the guts (the ... work ... part) of the commandLineRunner method to a new method in a new bean class e.g. #Component public class GenericRunner { public void run(String ... args) ... }.
This is the most important step: Delete the original CommandLineRunner #Bean definition in its entirety. This will cause the application's run() method to exit after performing configuration.
Replace the app.run(args); invocation with the following
ConfigurableApplicationContext ctx = app.run(); // oh yeah
GenericRunner runner = ctx.getBean(GenericRunner.class);
runner.run(args);
Re-run all tests, commit the code changes.
The actual refactoring is now trivial: modify the runner.run(args) call at will. This is just a straight call into the GenericRunner POJO and is free of SpringBoot rules and limitations.
SpringApplication class obviously doesn't have a method that gets this output stream, its an entry point to the complicated by very powerful spring boot application loading process.
If the goal is to store the log of the application consider logging configuration rather than using output streams.
Otherwise please describe the requirement, what is the purpose of this output stream and I'll do my best to update this answer.
Update:
SpringApplication starts up an application context that is used as a registry for spring beans in the application.
So the most "spring friendly solution is to define a ComplexObject to be a spring bean, so that it will be injected into other beans that might need it.
This will work great if this bean can be created during the application startup.
Example:
class ComplexObject {...}
class ServiceThatMaintainsAReferenceOnObject {
private ComplexObject complexObject;
// all arg constructor
}
#Configuration
class SpringConfiguration {
#Bean
public ComplexObject complexObject() {
return new ComplexObject();
}
#Bean
public ServiceThatMaintainsAReferenceOnObject service(ComplexObject complexObject) {
return new ServiceThatMaintainsAReferenceOnObject(complexObject);
}
}
Now, if this complex object has to be created outside the spring application, maybe you need to pass it to some bean method as a parameter, after the application context is created. This can also be a case in the question, although it's definitely not a Spring way to do things.
Here is an example:
class ComplexObject {}
class Service {
void foo(ComplexObject complexObject);
}
#Configuration
class MyConfiguration {
#Bean
public Service service() {
return new Service();
}
}
// inside the main class of the application:
SpringApplication app = ...
ComplexObject complexObject = ... // get the object from somewhere
ApplicationContext ctx = app.run(args);
// by this time, the context is started and ready
Service service = ctx.getBean(Service.class);
service.foo(complexObject); // call the method on bean managed by spring
All in all, usually the second approach is not a regular use case of spring application, although its kind of feels like you're looking for something like this in the question.
All-in-all I think you should learn and understand how Spring works in a nutshell, and what exactly the ApplicationContext is to provide the best solution (I'm sorry for mentioning this, I said so because from the question it looks like you haven't really worked with Spring and don't really understand what does it do and how does it manage the application).

How to dynamically inject a service using a runtime "qualifier" variable?

I can't find a simple way to inject a component/service given a runtime value.
I started reading # Spring's doc: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers
but I can't find there how to variabilize the values passed to the #Qualifier annotation.
Let's say I've got a model entity with such interface:
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
In my client code, I would do something like:
#Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
... with my service being:
#Service
public class DoService {
#Inject
// FIXME what kind of #$#& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
#Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
I expect the caseService to be the UKCaseService (see related code below).
public interface CaseService {
void modify(Case caze);
}
#Service
#Qualifier("uk")
public class UKCaseService implements CaseService {
}
#Service
#Qualifier("us")
public class USCaseService implements CaseService {
}
So how do I "fix" all of this in the most simple / elegant / efficient way by using either/all Spring feature(s), so essentially NO .properties, NO XML, only annotations.
However I already suspect something is wrong in my DoService because Spring would need to know the "case" before injecting the caseService... but how to achieve this without the client code knowing about the caseService?!
I can't figure this out...
I already read several issues here on SO, but most of the times either they don't really have the same needs and/or config as I have, or the posted answers aren't enough satisfying to me (look like they're essentially workarounds or (old) usage of (old) Spring features).
How does Spring autowire by name when more than one matching bean is found?
=> only refers to component-like classes
Dynamically defining which bean to autowire in Spring (using qualifiers)
=> really interesting but the most elaborated answer (4 votes) is... almost 3 1/2 years-old?! (July 2013)
Spring 3 - Dynamic Autowiring at runtime based on another object attribute
=> quite similar problem here, but the answer really look like a workaround rather a real design pattern (like factory)? and I don't like implementing all the code into the ServiceImpl as it's done...
Spring #Autowiring, how to use an object factory to choose implementation?
=> 2nd answer seems interestingly but its author does not expand, so altough I know (a bit) about Java Config & stuff, I'm not really sure what he's talking about...
How to inject different services at runtime based on a property with Spring without XML
=> interesting discussion, esp. the answer, but the user has properties set, which I don't have.
Also read this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references
=> I can't find expanded examples about the use of "#" in expressions. Does someone know about this?
Edit:
Found other related-to-similar issues, no one got a proper answer:
How to use #Autowired to dynamically inject implementation like a factory pattern
Spring Qualifier and property placeholder
Spring: Using #Qualifier with Property Placeholder
How to do conditional auto-wiring in Spring?
Dynamic injection in Spring
SpEL in #Qualifier refer to same bean
How to use SpEL to inject result of method call in Spring?
Factory Pattern might be a solution?
How to use #Autowired to dynamically inject implementation like a factory pattern
You can obtain your bean from the context by name dynamically using a BeanFactory:
#Service
public class Doer {
#Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
A side note. Using something like country code as bean name looks a bit odd. Add at least some prefix or better consider some other design pattern.
If you still like to have bean per country, I would suggest another approach. Introduce a registry service to get a required service by country code:
#Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
#Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Example usage:
#Service
public class DoService {
#Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
In this case you have to add String getCountryCode() method to your CaseService interface.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Alternatively, you can add method CaseService.supports(Case case) to select the service. Or, if you cannot extend the interface, you can call CaseServices.register(String, CaseService) method from some initialiser or a #Configuration class.
UPDATE: Forgot to mention, that Spring already provides a nice Plugin abstraction to reuse boilerplate code for creating PluginRegistry like this.
Example:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
#Service
#Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
#Service
#Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
#Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
#Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}
According to this SO answer, using #Qualifier isn't going to help you much: Get bean from ApplicationContext by qualifier
As for an alternative strategy:
if you are spring boot, you could use #ConditonalOnProperty or another Conditional.
a lookup service, as #aux suggests
just name your beans consistently and look them up by name at runtime.
Note that your use case also appears to revolve around the scenario where beans are created on application startup, but the bean chosen needs to be resolved after the applicationContext has finished injecting the beans.

What is the magic behind Field #Autowired

I am currently improving my Spring knowledge. I wonder what really happens when I use Spring annotation #Autowire on a field.
Here is a piece of code :
OutputHelper file
#Component
public class OutputHelper {
#Autowired
#Qualifier("csvOutputGenerator")
private IOutputGenerator outputGenerator;
public void setOutputGenerator(IOutputGenerator outputGenerator) {
this.outputGenerator = outputGenerator;
}
// I can focus only on what my code do because my objects are injected
public void generateOutput(){
outputGenerator.generateOutput();
}
}
CsvOutputGenerator file
#Component
public class CsvOutputGenerator implements IOutputGenerator {
public void generateOutput(){
System.out.println("Csv Output Generator");
}
}
Application file
public static void main(String[] args) {
// Create the spring context
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/spring-module.xml");
// Get the configured OutpuHelper from the spring-module.xml
OutputHelper output = (OutputHelper) context.getBean("outputHelper");
// Display output from the output configured
output.generateOutput();
}
My configuration file just contain <context:component-scan base-package="com.xxx.xxx.output"/>
When I execute this code all work fine. But what makes me surprised is when I delete the setOutputGenerator in OutPutHelper file, my piece of code keeps working. I tought that with this configuration, the OutputHelper was first created with default constructor and initialized with setter.
I expected an error because the variable outputGenerator was not be able to be initialized.
Is anyone can help me to understand ?
The idea to have fields #Autowired is questionable. It works, but it will difficult other aspects of your implementation (i.e. testing).
There are 3 types of injections:
fields - basically configured applying reflection (Field.set(Object, Object)) directly to the field:
#Autowired
private MyInterface field;
setters - with this approach the configuration of each dependency goes through a property (spring goes through all methods and execute each one annotated with #Autowired using Method.invoke(Object, Object...), thus its value is configured using its setter as follows:
#Autowired
public void setField(MyInterface value) {
this.field = value;
}
constructors - the last, and my preferable approach, the constructor injection. That one basically annotates an constructor with #Autowired and instead of using methods or fields, you can configure your bean directly on your constructor. For that spring will elect the a constructor to be used to instantiate your #Component, and it will use an #Autowired if existent or a empty params constructor, invoking it using Constructor.newInstance(Object...). Example:
#Component
public class Implementation {
private MyInterface field;
#Autowired
public Implementation(MyInterface value) {
Assert.notNull(value, "value should not be null");
this.field = value;
}
}
One of the ideas behind Inversion of Control (or Dependence Injection) is to be able to isolate a piece of code in order to provide decent test implementation support.
In order to go deeper, it is necessary to comment that during a unit test you want the class in its isolated form, all you will use with that class are basically mocks for its dependencies (injections).
So, what are the results:
If you do field injection, it will be quite costly to every single time set the beans using some reflection to configure the bean during your tests (another logic needs to be introduced to configure the bean to be tested).
With setter injection approach you will be able to use your own bean to configure it with mocks necessary to isolate your implementation and test its functionality.
And finally, with the constructor injection approach you will have not only the support to configure your bean, but you will be able to require its dependencies. This means that for every new dependency a new parameter on your constructor is added, this brings you come advantages on development time, for example, you will be able to see on development time the unit tests affected with the introduction of that new dependency (once your IDE will point it out for your).
Simple answer
Actually, the setter is useless, since the CDI use java Reflection to access fields.
It means that fields are no longer accessed by method calls.
Reflection allow iterating throught all fields of a class and check if there are annoted with a specific annotation.
In this case, if a field in your class is annoted With #Autowired (or #Inject wich is more J2E complient), the container will iterate throught searching if there is a registered bean that fits the current property.
Going deeper
When you context is starting, the container iterate classes and search all field annoted with #Inject or #Autowired.
For these fields, it search an available bean.
Here is the must simple example :
public class SpringClassInChargeOfDependencyInjection {
public void handdleInjections(T objectWithInjectableField) {
Class<T> clazz = objectWithInjectableField.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Inject.class)) {
//find a bean for the type;
Object injectableBean = getAvailablebean(field.getType());
field.setAccessible(true);
//inject the value into the class, this line explain why the setter is not necessary
field.set(objectWithInjectableField, injectableBean);
}
}
}
}
This is a non-working example just to explain how it works.
Tips
You might consider using #Inject instead of #Autowired, the later was created by Spring, #Inject is a part of the the JSR-330. Spring does understand #Inject as well, you just need to add the javax.inject jar dependency to your project. If later you want to switch from spring to something else (guice for example) you won't have to change all your #Autowired annotations
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>

Spring AOP: advice is not triggered

Trying to design simple aspect,that will print word "logg" to console,when any of public methods executed.
aspect:
#Aspect
public class LoggingAspect {
#Pointcut("execution(public * *(..))")
public void publicServices() {
};
#Before("publicServices()")
public void logg() {
System.out.println("logg");
}
}
xml config:
<context:component-scan base-package="aspectlogging" />
<aop:aspectj-autoproxy/>
<bean id="loggingAspectHolder" class="aspectlogging.LoggingAspect"/>
simple bean:
package aspectlogging;
#Component
public class TestableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
test:
public class TestLogging {
public static void main(String[] args) {
TestableBean tb = new TestableBean();
tb.setName("yes");
tb.getName();
}
}
I expect,that result of running of TestLogging will be "logg" word in console,and no output returned.
Do I understand AOP correctly in this case?
With #Around advice, you need to have a ProceedingJoinPoint pjp argument to the advising method and to call pjp.proceed() at the point in the advisor when you want the wrapped method to be called. It's easier to use #Before advice really, when what you've done will otherwise work just fine.
[EDIT]: Also, you must let Spring construct your beans for you instead of directly calling new. This is because the bean object is actually a proxy for your real object (which sits inside it). Because your target object doesn't implement an interface, you will need to have the cglib library on your classpath in addition to the Spring libraries. (Alternatively, you can go with using AspectJ fully, but that requires using a different compiler configuration.)
To create your beans, you first need to create a Spring context and then query that for the bean instance. This means you change from:
TestableBean tb = new TestableBean();
To (assuming you're using Spring 3, and that your XML config is in "config.xml" somewhere on your classpath):
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
TestableBean tb = context.getBean(TestableBean.class);
The rest of your code remains the same (after adjusting for import statements and possibly additional dependencies).
Not quite sure on this one, but maybe you need to use a spring managed TestableBean to have spring AOP pick up the method call.
edit: of course, you can't use #Around the way that you provided - but this subject has been addressed by another answer, so it's omitted here.
edit2: If you need help on how to get a spring managed bean, please feel free to ask. but since you already got your aspect bean set up, I believe you can handle this :)
edit3: Hehe. Ok.. maybe not :)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
will load your application context.
Load beans from there by calling:
TestableBean testableBean = (TestableBean )ctx.getBean("testableBean ");
Define the TestableBean just like you did with your Aspect bean.
edit4: Now I'm pretty sure that the fault is the non-spring managed bean.
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, then Spring AOP is the right choice. If you need to advise domain objects, or any other object not managed by the Spring container, then you will need to use AspectJ.
Taken from: http://static.springsource.org/spring/docs/2.0.x/reference/aop.html

Resources