I am Java JEE/Core developer working mainly on back-end systems but have also front-end experience. My religion is constantly imrove my developments skills according to best practises. My hands are also dirty from JavaScript, C++, Assembler and C#.
I'd like to show how to instantiate Spring's component with non-default constructor (constructor with parameters) from other Spring driven component because it seems to me that a lot of Java developers don't know that this is possible in Spring.
First of all, simple annotation based Spring configuration. It's scanning target package for components.
@Configuration
@ComponentScan("sk.lkrnac.blog.componentwithparams")
public class SpringContext {
}
Here is component with non-default constructor. This component needs to be specified as prototype, because we will be creating new instances of it. It also needs to be named (will clarify why below).
@Component(SpringConstants.COMPONENT_WITH_PARAMS)
@Scope("prototype")
public class ComponentWithParams {
private String param1;
private int param2;
public ComponentWithParams(String param1, int param2) {
this.param1 = param1;
this.param2 = param2;
}
@Override
public String toString() {
return "ComponentWithParams [param1=" + param1 + ", param2=" + param2
+ "]";
}
}
Next component instantiates ComponentWithParams. It needs to be aware of Spring's context instance to be able to pass arguments non-default constructor.
getBean(String name, Object... args) method is used for that purpose. First parameter of this method is name of the instantiating component (that is why component needed to be named). Constructor parameters follow.
@Component
public class CreatorComponent implements ApplicationContextAware{
ApplicationContext context;
public void createComponentWithParam(String param1, int param2){
ComponentWithParams component = (ComponentWithParams)
context.getBean(SpringConstants.COMPONENT_WITH_PARAMS,
param1, param2);
System.out.println(component.toString() + " instanciated...");
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = context;
}
}
Last code snippet is main class which loads Spring context and runs test.
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringContext.class);
CreatorComponent invoker = context.getBean(CreatorComponent.class);
invoker.createComponentWithParam("Fisrt", 1);
invoker.createComponentWithParam("Second", 2);
invoker.createComponentWithParam("Third", 3);
context.close();
}
}
It is well known that RCP bundle is not the Maven's best friend. Peacemaker between them is Maven's plug-in Tycho. I was recently migrating my free time RCP based project into Maven Tycho. My goal was to share dependencies between normal Maven project and Tycho driven project. Plain maven project is needed for running TestNG tests (TestNG is not supported by Tycho).
There are two approaches how to automatically handle dependencies of Eclipse 4 RCP based project driven by Tycho:
manifest-first - this approach follows standard RCP/OSGi dependency mechanisms. All dependencies has to be also assembled into bundles. This is preferred and nicely described in tutorial suggested by Tycho's website. It is hosted on github. But there are few problems complicating my goal:
It is needed to find existing bundle or create one for every dependency. Unhandy.
If I would use manifest-first approach, bundle dependencies wouldn't be visible by non Tycho maven projects. I would need to have two set of dependencies. Redundancy.
pom-first – this is alternative approach when dependencies are packed into bundle by maven-bundle-plugin and this is used as dependency to project's bundle. This approach is described here. Problem of this approach:
It is working only for Maven build and dependencies are not picked up by Eclipse.
Finally got the clue here (in the last approach) and came up with solution that is maybe not that pretty, but the dependencies are specified at one place and even Maven as well as Eclipse can pick them up. It is using some aspects both mentioned approaches.
I will show here only configuration crucial for my workaround. Whole project can be found on google code page. Let me describe maven projects structure:
discography-organizer.parent – contains various properties used by child poms. Is also used to run build of all sub-modules.
discography-organizer.dependencies.parent – shared dependencies are specified here
discography-organizer.dependencies.bundle – is doing two important steps:
And that's it. Dependencies needed by main bundle or test artifacts are packed into jar files. This workaround has side effects that I really don't like. Dependencies are ugly packed in one jar for main bundle. But I can live with that because this approach enables me to combine features of Tycho and non-Tycho maven plug-ins. I am planning to use another Tycho's features (automatic building and JUnit plug-in tests) and I have good start point for it.
If you can think of some simpler or more elegant solution please don't hesitate to comment it. Thanks