Java Weld CDI alternative Factory - java

In my production code I have an factory, this factory should be mocked in my test code.
I have an interface which both factories implement:
public interface FtpTransferFactory {
FtpTransfer createFtpTransfer(String host, String machine);
}
Production code:
#Default
public class FtpTransferFactoryImpl implements FtpTransferFactory {
public FtpTransferFactoryImpl() {
}
#Override
public FtpTransfer createFtpTransfer(final String host, final String machine) {
return new FtpTransfer(); // Some real ftp transfer object
}
}
Test code:
#Alternative
public class FtpTransferFactoryTestImpl implements FtpTransferFactory {
#Override
public FtpTransfer createFtpTransfer(String host, String machine) {
return ...; // Some real ftp transfer object, with different settings (test env)
}
}
In the beans.xml located at src/test/resources:
<alternatives>
<class>engine.FtpTransferFactoryTestImpl</class>
</alternatives>
My implementing class:
#Default
public class SomeClass
/** Ftp Factory */
#Default
#Inject
private FtpTransferFactory ftpFactory;
...
}
When I execute my unit tests my implementing class still ends up with the production factory instead of the test factory. However, when I put the -element into my src/main/resources (production) it does work. But I don't want that since i'm putting testing code into production code. I've seen several tutorials doing it via this method... what I'm a doing wrong?

The classes in src/main/resources and src/test/resources are two separate bean deployment archives (BDA). A beans.xml descriptor only affects the current BDA.
So your <alternative> definition only affects your test classes but not your production classes.
If you use CDI 1.1, you can make your alternative global (i.e. activate it for all BDAs in your application) by adding a #Priority annotation.
On CDI 1.0, you could try using #Specializes instead of #Alternative to override your default bean.

Related

Spring Boot 2 - Do something before the beans are initialized

Problem Statement
I want to load properties from a properties file in a classpath or at an external location before the beans are initialized. These properties are also a part of Bean initialization. I cannot autowire the properties from Spring's standard application.properties or its customization because the same properties file must be accessible by multiple deployables.
What I Tried
I'm aware about Spring Application Events; in fact, I'm already hooking
ContextRefreshedEvent to perform some tasks after the Spring Context is initialized (Beans are also initialized at this stage).
For my problem statement, from the description of Spring Docs ApplicationEnvironmentPreparedEvent looked promising, but the hook did not work.
#SpringBootApplication
public class App {
public static void main(String[] args) throws IOException {
SpringApplication.run(App.class, args);
}
#EventListener
public void onStartUp(ContextRefreshedEvent event) {
System.out.println("ContextRefreshedEvent"); // WORKS
}
#EventListener
public void onShutDown(ContextClosedEvent event) {
System.out.println("ContextClosedEvent"); // WORKS
}
#EventListener
public void onEvent6(ApplicationStartedEvent event) {
System.out.println("ApplicationStartedEvent"); // WORKS BUT AFTER ContextRefreshedEvent
}
#EventListener
public void onEvent3(ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent"); // WORKS WORKS BUT AFTER ContextRefreshedEvent
}
public void onEvent1(ApplicationEnvironmentPreparedEvent event) {
System.out.println("ApplicationEnvironmentPreparedEvent"); // DOESN'T WORK
}
#EventListener
public void onEvent2(ApplicationContextInitializedEvent event) {
System.out.println("ApplicationContextInitializedEvent"); // DOESN'T WORK
}
#EventListener
public void onEvent4(ApplicationContextInitializedEvent event) {
System.out.println("ApplicationContextInitializedEvent");
}
#EventListener
public void onEvent5(ContextStartedEvent event) {
System.out.println("ContextStartedEvent");
}
}
Update
As suggested by M.Deinum in the comments, I tried adding an application context initializer like below. It doesn't seem to be working either.
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(App.class)
.initializers(applicationContext -> {
System.out.println("INSIDE CUSTOM APPLICATION INITIALIZER");
})
.run(args);
}
Update #2
While my problem statement is regarding loading properties, my question/curiosity is really about how to run some code before the classes are initialized as beans and put into Spring IoC container. Now, these beans require some property values during initialization and I can't/don't want to Autowire them because of the following reason:
As stated in comments and answers, the same can be done using Spring Boot's externalized configuration and profiles. However, I need to maintain application properties and domain-related properties separately. A base domain properties should have at least 100 properties, and the number grows over time. Both application properties and domain-related properties have a property file for different environments (dev, SIT, UAT, Production). Property files override one or more of the base properties. That's 8 property files. Now, the same app needs to be deployed into multiple geographies. That makes it 8 * n property files where n is the number of geographies. I want all the property files stored in a common module so that they can be accessed by different deployables. Environment and geography would be known in run-time as system properties.
While these might be achieved by using Spring profiles and precedence order, I want to have a programmatic control over it (I also would maintain my own property repository). Eg. I would write a convenience utility called MyPropUtil and access them like:
public class MyPropUtil {
private static Map<String, Properties> repository;
public static initialize(..) {
....
}
public static String getDomainProperty(String key) {
return repository.get("domain").getProperty(key);
}
public static String getAppProperty(String key) {
return repository.get("app").getProperty(key);
}
public static String getAndAddBasePathToAppPropertyValue(String key) {
...
}
}
#Configuration
public class MyComponent {
#Bean
public SomeClass getSomeClassBean() {
SomeClass obj = new SomeClass();
obj.someProp1(MyPropUtil.getDomainProperty('domainkey1'));
obj.someProp2(MyPropUtil.getAppProperty('appkey1'));
// For some properties
obj.someProp2(MyPropUtil.getAndAddBasePathToAppPropertyValue('some.relative.path.value'));
....
return obj;
}
}
From the docs, it seems like ApplicationEvents and ApplicationInitializers fit my need, but I am not able to get them to work for my problem statement.
Bit late to the party but hopefully I can offer a solution to your updated problem statement.
This will focus on problem of how to run some code before the classes are initialized as beans and put into Spring IoC container
One issue I notice is that you're defining your application events via the #EventListener annotation.
These are only called once all beans are initiated since these annotations are processed by EventListenerMethodProcessor which is only triggered when the context is ready (see SmartInitializingSingleton#afterSingletonsInstantiated)
As such, some of the events that occur before the context is ready. e.g. ContextStartedEvent, ApplicationContextInitializedEvent won't make it to your listener.
Instead, what you can do is extend the interface for these events directly.
#Slf4j
public class AllEvent implements ApplicationListener<ApplicationEvent> {
#Override
public void onApplicationEvent(final ApplicationEvent event) {
log.info("I am a {}", event.getClass().getSimpleName());
}
Note the missing #Component. Even bean instantiation can occur after some of these events. If you use #Component, then you'll get the following logs
I am a DataSourceSchemaCreatedEvent
I am a ContextRefreshedEvent
I am a ServletWebServerInitializedEvent
I am a ApplicationStartedEvent
I am a ApplicationReadyEvent
Still better and more instant than the annotative listeners but will still not receive the initialization events. For that, what you need to do is follow the instructions found here
To summarize,
Create directory resources/META-INF
Create file spring.factories
org.springframework.context.ApplicationListener=full.path.to.my.class.AllEvent
The result:-
I am a ApplicationContextInitializedEvent
I am a ApplicationPreparedEvent
I am a DataSourceSchemaCreatedEvent
I am a ContextRefreshedEvent
I am a ServletWebServerInitializedEvent
I am a ApplicationStartedEvent
I am a ApplicationReadyEvent
In particular, ApplicationContextInitializedEvent should allow you to perform whatever per-instantiation tasks you need.
I think Spring Cloud Config is a perfect solution for your problem statement. Detailed documentation Here
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system.
So you can easily manage the configurations outside of the app, as well as all the instances will use same configurations.
Create a bean that will be a properties repository and inject it in other beans requiring properties.
In your example, instead of having static methods in MyPropUtil, make the class a bean itself with instance methods. Initialize Map<String, Properties> repository in the initialize method annotated with #PostConstruct.
#Component
public class MyPropUtil {
private static final String DOMAIN_KEY = "domain";
private static final String APP_KEY = "app";
private Map<String, Properties> repository;
#PostConstruct
public void init() {
Properties domainProps = new Properties();
//domainProps.load();
repository.put(DOMAIN_KEY, domainProps);
Properties appProps = new Properties();
//appProps.load();
repository.put(APP_KEY, appProps);
}
public String getDomainProperty(String key) {
return repository.get(DOMAIN_KEY).getProperty(key);
}
public String getAppProperty(String key) {
return repository.get(APP_KEY).getProperty(key);
}
public String getAndAddBasePathToAppPropertyValue(String key) {
//...
}
}
and
#Configuration
public class MyComponent {
#Autowired
private MyPropUtil myPropUtil;
#Bean
public SomeClass getSomeClassBean() {
SomeClass obj = new SomeClass();
obj.someProp1(myPropUtil.getDomainProperty("domainkey1"));
obj.someProp2(myPropUtil.getAppProperty("appkey1"));
// For some properties
obj.someProp2(myPropUtil.getAndAddBasePathToAppPropertyValue("some.relative.path.value"));
//...
return obj;
}
}
Or you can inject MyPropUtil directly to the SomeClass:
#Component
public class SomeClass {
private final String someProp1;
private final String someProp2;
#Autowired
public SomeClass(MyPropUtil myPropUtil) {
this.someProp1 = myPropUtil.getDomainProperty("domainkey1");
this.someProp2 = myPropUtil.getAppProperty("appkey1");
}
//...
}
I feel like your main issue is that you need to maintain application properties and domain-related properties separately.
From spring's perspective, it doesn't really matter since all properties files are kinda merged together after they have been loaded in memory.
So for example, you have two files that contain some properties:
application.related=property1 # this is in application.properties
domain.related=property2 # this is in domain-specific.properties
After they have been loaded, you will get one big thing that contains all properties, if I am not mistaken, it is a org.springframework.core.env.ConfigurableEnvironment instance.
Then what you need to do is just inject the property you need using something like #Value.
For the main issue, to separate properties into different files, you just need to specify spring's spring.config.name property (via environment variable, command line or programmatically). Following the above example, it should be spring.config.name=application,domain-specific.
Furthermore, if you really want to have programmatic control, you can add a custom EnvironmentPostProcessor which exposes the ConfigurableEnvironment instance.
As explaned in this post you can add external property files like this;
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("/Users/home/conf.properties"));
properties.setIgnoreResourceNotFound(false);
return properties;
}
If you don't want to use this, just read the property file with jackson and set the properties to System.setProperty("key","value") in the main method before spring starts.
If you don't want to use this too, take a look at the BeanPostProcessor#postProcessBeforeInitialization method. It runs before bean properties initialized by spring.
I might be missing what exactly do you mean by "Beans initialization", probably an example of such a bean in a question could be beneficial.
I think you should differentiate between properties reading part and bean initialization.
By the time of bean initialization, properties are already read and available. Thats a part of spring magic, if you wish.
That's why the following code works for example:
#Component
public class MySampleBean {
public MySampleBean(#Value("${some.prop}" String someProp) {...}
}
It doesn't matter from where do these property come (spring boot defines many different ways of these places with precedence between them), it will happen before the initialization of beans happens.
Now, lets get back to your original question:
I want to load properties from a properties file in a classpath or at external location (before the beans are initialized - irrelevant).
In spring / spring-boot there is a concept of profiles that basically allows to create a file application-foo.properties (or yaml) and when you load with --spring.profiles.active=foo it will automatically load properties defined in this application-foo.properties in addition to the regular application.properties
So you can place the stuff that you want to "load from classpath" into application-local.properties (the word local is for the sake of example only) and start the application with --spring.profiles.active=local (in the deployment script, docker file or whatever)
If you want to run the property from external location (outside the classpath) you can use: --spring.config.location=<Full-path-file>
Note that even if you put some properties into a regular application.properties and still use --spring.config.location with the same key-value pairs they will take precedence over the properties in the classpath.
Alternatively you can use only --sring.profiles.active=local or remote and do not use config locations at all.
You can configure external location directly in the command line:
java -jar app.jar --spring.config.location=file:///Users/home/config/external.properties
You can use WebApplicationInitializer to execute code before classes are initialized as beans
public class MyWebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
var ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);
We create an AnnotationConfigWebApplicationContext and register a web configuration file with register().
You can check if PropertySource may help you.
Example:
#PropertySource({"classpath:persistence/persistence.properties"})
You can use this annotation on every #Configuration or #SpringBootApplication bean
It sounds like you want to take some ownership of a part of the bean initialization. Typically people think of Spring completing the bean configuration, but in your case it might be easier to consider Spring as starting it.
So, your bean has some properties you want to configure, and some that you want Spring to configure. Just annotate the ones you want Spring to configure (with #Autowire or #Inject, or whatever flavour you prefer), and then take over the control from there, using #PostConstruct or InitializingBean.
class MyMultiStageBoosterRocket {
private Foo foo;
private Bar bar;
private Cat cat;
#Autowire
public MyMultiStageBoosterRocket(Foo foo, Bar bar) {
this.foo = foo;
this.bar = bar'
}
// called *after* Spring has done its injection, but *before* the bean
// is registered in the context
#PostConstruct
public void postConstruct() {
// your magic property injection from whatever source you happen to want
ServiceLoader<CatProvider> loader = ServiceLoader.load(CatProvider.class);
// etc...
}
}
Of course your mechanism for property resolution would need to be available statically somehow, but that seems to fit with you MyPropUtil example.
Getting far more involved, you start looking at Bean Post Processors directly (#PostConstruct is a simple variant of sorts).
There's a previous question, with a useful answer, here How exactly does the Spring BeanPostProcessor work?, but for simplicity, you'd do something like
public class CustomBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// fixme: detect if this bean needs fancy initialization
return bean;
}
}
Clearly #PostProcess, or InitializingBean are simpler, but the custom post processor has a big advantage... it can be injected with other Spring managed beans. That means you can Spring manage your property injection whatever-thing, and still manually manage the actual injection process.
Just try to load everything you need in main before
SpringApplication.run()
call
public static void main(String[] args) {
// before spring initialization
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SpringApplication.run(CyberRiskApplication.class, args);
}
You can use ApplicationEnvironmentPreparedEvent but it can't be configured using EventListener annotation. Because by this time Bean drfinitions are not loaded. See the below link on how to cofigure this event.
https://www.thetechnojournals.com/2019/10/spring-boot-application-events.html

EJB 3.1 Unit Test, two Beans, one #DependsOn the other, exchange through mock

I currently working on my first EJB project with Glassfish 3.1.2.2. I have two beans:
#Singleton
#Startup
public class ABean implements AInterface {
//implementation
}
and
#DependsOn("ABean")
#Startup
#Singleton
#EJB(name = "ABean", beaninterface = AInterface)
public class BBean implements BInterface {
//implementation
}
I want to unit test the "BBean" and mock the "ABean". Currently, when I'm starting the JUnitTest the "ABean" will be started but is there a way to exchange the "ABean" with a "ABeanMock"?
I need a automatic mechanism to exchange the implementation with the mock as these tests will be run on a jenkins server. So a manual adoption of the code is ok for single manual test but cannot be made for automatic testing.
I'm using the Glassfish Embedded API for unit tests.
Thanks for help.
You can use Arquillian for this.
Arquillian runs your tests inside a container, deploying to an application server if necessary. You can choose to use selected classes only, so this would allow you to create a replacement ABean that implements AInterface, and choose not to deploy the real ABean - which would result in your replacement being used instead.
The test would look something like this:
#Singleton(name = "ABean")
class AMockBean implements AInterface {
// Mocked bean implementation
}
#RunsWith(Arquillian.class)
public class MyTests {
#Inject
private BBean bbean;
#Deployment
public Archive<?> deployment() {
return ShrinkWrap.create(JavaArchive.class)
.addClass(BBean.class)
.addClass(AMockBean.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}
#Test
public void testBBean() {
bbean.whatever();
}
}
This is all untested, but it should be something along the lines of this. Depending on your environment and dependencies, it might be more difficult to configure correctly.
Arquillian is a wonderful tool, but it can be difficult to set up exactly the way you want it when starting out. Luckily there are several guides to help you through the process.

Java: How custom DI configuration works for WARs and EARs

I have written a Bootstrapper class that reads an XML file from the classpath and can be used as a lightweight dependency injector by other classes at runtime:
<!-- myAppConfig.xml -->
<appConfig>
<environment runningOn="LOCAL" host="localhost.example.com" system="Windows 7"/>
</appConfig>
public class Bootstrapper
{
private String runningOn = "Unknown";
private String host = "Unknown";
private String system = "Unknown";
public Bootstrapper(final String appConfigFileName)
{
setRunningOn(extractRunningOn(appConfigFileName));
setHost(extractHost(appConfigFileName));
setSystem(extractSystem(appConfigFileName));
}
public String getHost()
{
return host;
}
// Rest of class ommitted for brevity...
}
// Then in an executable JAR's main method:
public static void main(String[] args)
{
Bootstrapper bootstrapper = new Bootstrapper("myAppConfig.xml");
// Prints: "This app is running on the localhost.example.com server node."
System.out.println("This app is running on the " +
bootstrapper.getHost() + " server node.");
}
In this sense appConfig and Bootstrapper kind of serve as ultra lightweight "DI" mechanisms.
What I'm wondering is: how do I translate this design to a WAR's web.xml and an EAR's server.xml?
Whereas in an executable JAR, the main method explicitly instantiates a Bootstrapper which can then be interrogated for its fields/properties, in a WAR/EAR everything is defined in an XML file (web.xml/server.xml) without a single "entry point". So in a WAR or EAR, if I had multiple classes that each needed to know what the local host name was, I would have to keep instantiating the same Bootstrapper over and over again, passing it the same myAppConfig.xml each time.
I'm wondering if there's a way to configure web.xml and server.xml to instantiate a Bootstrapper on startup/deployment, and to automatically inject/populate my dependent classes right then and there (or, at the very least, to give each dependent class access to the global/singleton Bootstrapper defined in the XML file).
Thanks in advance!
For a war (and an ear since it will contain a war) project you could use a ServletContextListener to instantiate your Bootstrapper.
A good example of how to use a ServletContextListener is here.
However if you are using Java EE 6 then a better way to do this would be to use an EJB 3.1 Singleton and some CDI.
import javax.ejb.Singleton
import javax.ejb.Startup
import javax.enterprise.context.ApplicationScoped
#Singleton // EJB 3.1 Singleton
#Startup // Telling the container to eagerly load on startup
#ApplicationScoped // CDI Scope
public class Bootstrapper {
private String host = "Unknown";
#PostConstruct
public void readConfiguration() {
// ... load your xml file
}
public String getHost() {
return host;
}
}
Using the above you can now inject this Bootstrapper bean within most of the EE 6 ecosystem with a simple #Inject or #EJB annotation.

Injecting dependencies using #Autowired into objects created with "new ..."

I have a problem with injecting a bean into a helper class. It works basically like this: I create an object in the page constructor that does some work, returns some data and I show these on the page. In this helper object, a service should be injected via #Autowired annotation. However, I always get a null pointer exception when I use it. I also tried #SpringBean but it didn't help. On the other hand, when I inject this service directly into the page with #SpringBean, it's accessible and works fine. Do you know where the problem is?
This is the page:
public class Page extends BasePage {
public Page() {
HelperObject object = new HelperObject(new Application("APP_NAME"));
String result = object.getData();
add(new Label("label", result));
}
}
Helper object:
public class HelperObject {
private Application app;
#Autowired
private Service service;
public HelperObject(Application app) {
this.app = app;
}
public String getData() {
// use service, manipulate data, return a string
}
}
You can inject dependencies into non-Spring-non-Wicket-new-created objects using #SpringBean by calling InjectorHolder.getInjector().inject(this); in its constructor.
For example:
class MyPojo {
#SpringBean
MyDumbDAO dao;
MyPojo() {
InjectorHolder.getInjector().inject(this);
}
void justDoIt() {
dao.duh(); // dao is there!
}
}
Note that it will only work if called within a Wicket-managed request. If not (ie, if it's a Quartz job, or a Filter executed before Wicket's), the Application instance will not be available, and the injector won't know how to get the dependencies.
Another solution is to use Spring's #Configurable. It uses AspectJ to intercept creation of annotated objects, and inject its dependencies, even if you instantiate them directly with new (or some other framework, like Hibernate, creates them internally). But this requires runtime or build-time (works better for me) bytecode manipulation, which may be too much magic for some people.
#SpringBean only injects dependencies into classes that inherit from Wicket's Component. #Autowired only injects dependencies into classes created by Spring itself. That means you can't automatically inject a dependency into an object you create with new.
(Edit: you can also add a #SpringBean injection to your class by injecting in the constructor:
InjectorHolder.getInjector().inject(this);)
My normal workaround for this is to use my application class to help. (I'm a little puzzled by your use of new Application(...). I assume this isn't actually org.apache.wicket.Application.) For example:
public class MyApplication extends AuthenticatedWebApplication implements
ApplicationContextAware {
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
public static MyApplication get() {
return (MyApplication) WebApplication.get();
}
public static Object getSpringBean(String bean) {
return get().ctx.getBean(bean);
}
public static <T> T getSpringBean(Class<T> bean) {
return get().ctx.getBean(bean);
}
....
}
In my Spring application context:
<!-- Set up wicket application -->
<bean id="wicketApplication" class="uk.co.humboldt.Project.MyApplication"/>
My helper object then looks up the service on demand:
public class HelperObject {
private Service getService() {
return MyApplication.getSpringBean(Service.class);
}
The best practice would be to create your objects via a factory bean (that has those properties injected by Spring, and have that factory inject those properties to objects it spawns - pure IoC).
You should really avoid using SpringContext all over the place (or any other similar solution for that matter).
Here is a partial list of reasons:
Your code gets coupled with Spring way too much (low-cohesion).
You mix plumbing code with the business-logic.
Your code is less readable.
It's less maintainable (e.g., changing the name of the service bean would lead to code modification - this violates SRP & OCP).
It's less testable (e.g., you need the Spring framework to test it).

How do I configure JSR-330 #Provider and #Inject #Named("foo") String **programmatically** in Spring?

We have decided to use Dependency Injection with JSR-330 annotations for our future modularization efforts, and have been very pleased with the first deliverable based on Guice 2 SVN.
Now we need to ensure and document through unit tests that the constructions we need, also work in Spring when configured programmatically (we want the same refactoring support as with Guice so no XML files). I have problems with #Provider and #Inject #Named("foo") String but I have made plain #Inject work with:
ApplicationContext ctx = new AnnotationConfigApplicationContext(LIBL_Object.class,
CORE_Provider.class);
this.object = ctx.getBean(LIBL_Object.class);
where LIBL_Object is the base class to be injected into, but the CORE_Provider does not register as I hoped within Spring.
The implementation of CORE_Provider is
package qa.jsr330.core;
import javax.inject.Provider;
public class CORE_Provider implements Provider<ProvidedInterface> {
#Override
public ProvidedInterface get() {
return new CORE_Provided();
}
}
and I want it injected into
package qa.jsr330.core;
import javax.inject.Inject;
public class LIBL_Object {
private ProvidedInterface provided;
public ProvidedInterface getProvided() {
return provided;
}
#Inject
public void setProvided(ProvidedInterface provided) {
this.provided = provided;
}
// Other stuff omitted.
}
Also we have found that we can pass configuration values very clearly using the #Named tag. This code looks like:
String hostname;
#Inject
public void setHostname(#Named("as400.hostname") String hostname) {
this.hostname = hostname;
}
where we can then register this string with Guice using
bindConstant().annotatedWith(Names.named("as400.hostname")).to(value);
So the two questions are:
How do I register the #Provider class with Spring 3 programatically?
How do I register a string constant with Spring 3 so that #Named selects it properly?
The short answer is: there is no such thing as programmatic configuration of Spring.
Despite the fact that both Spring and Guice support JSR-330 API and that Spring can be configured without XML now, their ideologies are still very different. Spring relies on static configuration, either in the form of XML files or annotated Java classes. Therefore straightforward attempt to adapt Guice-style configuration to Spring may produce difficulties.
Regarding the problem with Provider - Spring doesn't support javax.inject.Provider in the same way as toProvider() binding in Guice (by the way, this usage of Provider is not specified in JSR-330 docs). Therefore some Spring-specific annotations may be needed, for example
#Configuration
public class CORE_Provider implements Provider<ProvidedInterface> {
#Override #Bean
public ProvidedInterface get() {
return new CORE_Provided();
}
}
Binding value coming from the outside may be difficult due to static nature of Spring configuration. For example, in your case, it can be done like this:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(IBL_Object.class);
ctx.register(CORE_Provider.class);
ctx.registerBeanDefinition("as400.hostname",
BeanDefinitionBuilder.rootBeanDefinition(String.class)
.addConstructorArgValue(value).getBeanDefinition());
ctx.refresh();

Categories

Resources