how to change/set a binding by a property/string given in a property/text file? in my case i want to implement a kind of "demo mode".
In normal mode a property gives an url to an external service but if url is "demo" the binding of the according interface should be changed like this:
normal:
bind(SasDatenProvider.class).to(SasDataProviderHttpImpl.class);
demo
bind(SasDataProvider.class).to(SasDataProviderFileImpl.class);
how to achieve that?
thx in advance
You can use a method annotated with #Provides in your module. Then you can do something like this:
public class MyModule extends AbstractModule {
#Provides
SasDatenProvider provideSas(SasDataProviderHttpImpl http,
SasDataProviderFileImpl file){
boolean isDemo = false; /* do you property lookup logic here */
return isDemo ? file : http;
}
}
You can read more about #Provides-methods in the guice docs:
http://code.google.com/p/google-guice/wiki/ProvidesMethods
If your don't want this kind of logic in you module, you can consider creating your own provider:
http://code.google.com/p/google-guice/wiki/ProviderBindings
Related
I'm trying to understand how to handle conditionally creating new instances of a class that uses #Inject. In the below example I have a factory that instantiates classes based on a parameter.
AnimalFactory does not have access to the injector the main class of my application has, so I can't use injector.getInstance(Cat.class)
class AnimalFactory {
public IAnimal create(AnimalType type) {
if (type.equals(AnimalType.CAT)) {
return new Cat(); // Cat uses #Inject, so this won't work of course. But ???
} else if (type.equals(AnimalType.DOG)) {
return new Dog();
}
}
}
In the rest of my app, classes are injected into my constructors because I always need them. Guice creates an instance/singleton for each. But in this scenario, I do not want to create and inject instances for each animal because all but one are needed.
You can use a MapBinder as described here:
public class AnimalModule extends AbstractModule {
public void configure() {
MapBinder<AnimalType, IAnimal> animalBinder= MapBinder.newMapBinder(binder(), AnimalType.class, IAnimal.class);
animalBinder.addBinding(AnimalType.DOG).to(Dog.class);
...
}
}
And than use it in your factory:
class AnimalFactory {
#Inject
Map<AnimalType, IAnimal> animals;
public IAnimal create(AnimalType type) {
return animals.get(type);
}
}
Actually I worked on exactly the same issue and I wrote a feature that allows you to create self-populating factory. Meaning that if you work in Spring/Spring-boot environment you can create a factory that can access and provide any interface implementing class that is managed by Spring-boot without injecting in the factory. You can also give the instances custom names. So, it seems like it fits your case exactly. Here is a link to an article that describes the feature in great detail: Non-intrusive access to "Orphaned" Beans in Spring framework. Also, in MgntUtils library Javadoc there is a good description of the feature here enter link description here. The library itself including source code could be found on Github here and in the package com.mgnt.lifecycle.management.example there is a working example. Maven artifacts are here
For example, let's say that in my yml file I had a variable called indicator. And based on what the indicator variable's value was I want the code to do something different. How would I access the yml variable in the regular code and use it accordingly?
You can use this:
#Value("${your.path.yml.string}")
private String x;
YML:
your:
path:
yml:
string: hello
x will be "hello"
You need to use Spring Expression Language which says we should write it as
#Value("${spring.application.name}")
private String appName;
For Default value if key is not present in yaml/yml or properties file
#Value("${spring.application.name: defaultValue}")
private String appName;
The last way you can fetch value is using environment object
#Autowired
private Environment environment;
String appName = environment.get("spring.application.name");
You can add #Value annotation to any field in your beans.
#Value("$(path.to.your.variable)")
String myString;
Works with constructors as well.
public MyClass(#Value("$(path.to.your.variable)") String myString) {
You can use #Value on fields or parameters to assign the property to some variable.
Property example:
#Value("${indicator}")
private String indicator
Parameter example:
private void someMethod(#Value("${indicator}") String indicator) {
...
}
Then you can use indicator as you want.
Note: the class where you use #Value should be a Spring Component
With Spring-Boot, you have the file application.yml automatically provided for you. What you can do is adding a property in this file, for instance:
my.properties: someValue
Then, in one of your Spring Bean (either define with #Component or #Bean) you can retrieve this value using the annotation #Value. Then, do whatever you want with this variable.
For instance:
#Component
public class MyClass {
#Value("${my.properties"}
private String myProp; // will get "someValue" injected.
...
// Just use it in a method
public boolean myMethod() {
if(myProp.equals("someValue") {
// do something
} else {
// do something else
}
}
}
The best way to do this is not to have a tight coupling between Spring and your "normal" code at all, but instead to use the normal Java features like constructors along with Spring #Bean methods:
class MyService {
final String indicatorName;
MyService(String indicatorName) {
this.indicatorName = indicatorName;
}
}
... in your configuration class...
#Bean
MyService myService(#Value("indicator.name") String indicatorName) {
return new MyService(indicatorName);
}
Two notes for Spring Boot specifically:
The #ConfigurationProperties feature allows you to map properties onto structured Java data classes and is typically cleaner than using #Value by hand.
Always namespace properties that you define yourself to avoid future collisions with other libraries, so instead of indicator.name use company.project.indicator.name. I recommend looking at DataSourceProperties in Boot to see an example of how to set all this up.
More broadly, though, when you say that you want the code to "do something different", it sounds like the better option might be to have different classes that get activated under different circumstances. Both Spring profiles and Spring Boot auto-configuration help to do this.
The problem statement can be re-defined as Configuration Management in Java.
You should have a component like ConfigManager that gets instantiated as part of your application start up. That component will read a properties file, a yaml in your use case. Subsequent app logic will fetch these values from the ConfigManager exposed as simple key/value pairs.
All that is left for you to identify how to read and parse values from yaml file. This is already answered here:
Parse a YAML file
I am working on a project that uses dropwizard's hibernate bundle to get a session factory per the below docs:
http://www.dropwizard.io/0.7.1/docs/manual/hibernate.html
The project doesn't use any xml and only uses annotated classes for the configuration of the bundle just like in the example.
public class ExampleConfiguration extends Configuration {
#Valid
#NotNull
#JsonProperty("database")
private DataSourceFactory database = new DataSourceFactory();
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
private final HibernateBundle<ExampleConfiguration> hibernate =
new HibernateBundle<ExampleConfiguration>(
some.class
) {
#Override
public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
However, we have a use case where I need to prepend the environment to the table name of the DAO objects such that the #Table annotation gets overwritten.
I have a class which implements ImprovedNamingStrategy, per the below docs
http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/ImprovedNamingStrategy.html
But how do I hook the naming strategy into my dropwizard hibernate bundle. I would like to be able to do something like this...
hibernateBundle.setNamingStrategy(ImprovedNamingStrategy.Instance)
or
hibernateBundle.addAnnotatedClass(someHibernateNamingPropertyConfig)
https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/cfg/Configuration.html#setNamingStrategy(org.hibernate.cfg.NamingStrategy)
However, the hibernateBundle API doesn't allow for any of this.
Looking through the source code of HibernateBundle
https://github.com/dropwizard/dropwizard/blob/master/dropwizard-hibernate/src/main/java/io/dropwizard/hibernate/HibernateBundle.java
You can see that it uses "import io.dropwizard.Configuration;" as opposed to org.hibernate.cfg which does expose all of these methods. I'm trying to avoid a major refactor so if there is a "hacky" way to force set the naming property on the bundle, then I'm okay with that.
Any ideas of where to go from here would be much appreciated.
Found a solution for this that works for me in Dropwizard 0.8.4. Not sure if it can help you with Dropwizard 0.7.1, but it will definitely be helpful for readers coming from Google with the same question.
You can extend HibernateBundle and override configure(). This method is called just before SessionFactoryFactory is going to be built, with the Configuration object for it. You can then override the method to add any special configurations you might need.
Example:
public abstract class DatabaseWithImprovedNamingStrategyBundle extends ScanningHibernateBundle {
public DatabaseWithImprovedNamingStrategyBundle(String pckg) {
super(pckg);
}
#Override
protected void configure(Configuration configuration) {
super.configure(configuration);
configuration.setNamingStrategy(ImprovedNamingStrategy.INSTANCE);
}
}
This example uses ScanningHibernateBundle because it's the one I was using, but you can use HibernateBundle directly too.
I just decided not to use the Hibernate Bundle and create a second config object which reads values out of the Hibernate Bundle.
I'm using a rest service with AndroidAnnotations, configured like so:
#Rest(rootUrl = "http://192.168.1.48:8080/stuff/services/rest/StuffService/",
converters = {MappingJacksonHttpMessageConverter.class})
public interface IStuff
{
#Post("fetchAllStuff")
public Response fetchAllStuff(Request req);
}
So what happens when I need to change the URL at runtime? If the URL is hard-coded in the annotation, what would I do to change it? Is there some way I could have it in a properties or XML file as well?
As explained on the wiki, you can simply define a void setRootUrl(String rootUrl) method and it will be generated as a setter on the final class
I am looking for a way to do the following:
A Project :
Defines an abstract class that is called when some events happen (event handler if you will)
Defines the engine that will fire the events using the event handler above
B Project:
Defines the implementation for the abstract class
Runs the engine.
How can i register the implementation class and make sure that is the one being called when the engine runs.
EDIT 1: By register i mean i must somehow define which is the implementation that should be called for that given abstract object
Sorry if the question isn't too clear, let me know if you need some more details
Something like this?
class A implements EventHandlerForB {
...
}
public class B {
private EventHandlerForB eventHandler;
public void registerEventHandler(EventHandlerForB eventHandler) {
this.eventHandler = eventHandler;
}
...
}
public interface EventHandlerForB {
...
}
At runtime, you can have the name of the implementation passed in your A project (with a properties file or a Java system property).
Then you find this class in the classpath with class.forName() and instantiate it with newInstance().
But you'd prefer using a framework like Guice or Spring, that will allow you to glue stuff together in a clean way.
there are several "patterns" that try to address this issue. Using only JDK (6 or above) classes you may want to take a look at java.util.ServiceLoader