We are actually using Spring Boot's #ConfigurationProperties as basically a configuration mapper : it provides us an easy shortcut to map properties on objects.
#ConfigurationProperties("my.service")
public class MyService {
private String filePrefix;
private Boolean coefficient;
private Date beginDate;
// getters/setters mandatory at the time of writing
public void doBusinessStuff() {
// ...
}
}
Although this was a nice productivity boost when we were prototyping the app, we came to question if this was right usage.
I mean, configuration properties have a different status in Spring Boot's context, they're exposed through actuator endpoints, they can be used to trigger conditional beans, and seem more oriented toward technical configuration properties.
Question : Is it "correct" to use this mechanism on any business property/value, or is it plain misuse ?
Any potential drawback we missed ?
Right now our only concern is that we cannot use #ConfigurationProperties on immutable classes, which is closely related to this issue on Spring Boot's tracker : Allow field based #ConfigurationProperties binding
If your property represents something that is configurable based on the environment/profile that is what the mechanism is there for. Though I'm a little unclear what you mean by
"map properities on objects".
I would not favor this style in general, especially if your bean has multiple properties to set. A more standard idiom is to have a class that encapsulates the properties/settings used to create your bean:
#ConfigurationProperties("my.service")
public class MyServiceProperties {
private String filePrefix;
private Boolean coefficient;
private Date beginDate;
// getters/setters mandatory at the time of writing
}
then your Service class would look like this:
#EnableConfigurationProperties(MyServiceProperties.class)
public class MyService {
#Autowired
private MyServiceProperties properties;
//do stuff with properties
public void doBusinessStuff() {
// ...
}
}
This would at least allow you to pass the properties easily into an immutable class through it's constructor (make copies of any mutable properties). Also having the properties bean can be reused if you find other parts of your app need some shared configuration.
Consider this example
#Stateless
public class UniqueIdGenerator {
private static final String COLON = ":";
private String serverPrivateKey;
#SuppressWarnings("UnusedDeclaration")
public UniqueIdGenerator() {
}
#Inject
public UniqueIdGenerator(#Nonnull final String serverPrivateKey) {
this.serverPrivateKey = serverPrivateKey;
}
...
}
I would like to #Inject value of serverPrivateKey based on an environment variable available in different environments.
What is the best way to inject it here?
To inject values from the environment, rather than writing your own producer methods, you may want to have a look at the Configuration API of Apache DeltaSpike.
Using a #ConfigProperty qualifier, you can inject values from a number of different property sources, like system properties, environment variables or JNDI.
Example:
#Inject
#ConfigProperty(name = "SERVER_PRIVATE_KEY")
private String serverPrivateKey;
We use the following pattern: There is a bean which gives us the value which we need. The bean knows how to get the value (environment, System property, whatever). To make things easier later, the type of the bean should be an interface (in your case that might be IPrivateKeyProvider).
The UniqueIdGenerator is then created and we inject the first bean. The setup then decides which bean this will be (some kind of mock for tests and a real implementation for production code).
You will have to use producer Method :
According to related oracle documentation :
A producer method generates an object that can then be injected. Typically, you use producer
methods in the following situations:
[...]
When the concrete type of the object to be injected may vary at runtime
See an example here
So I have a class like so:
public class HBaseUtil {
private final String fileName = "hbase.properties";
private Configuration config;
private HBaseUtil() {
try {
config = new PropertiesConfiguration(fileName);
} catch (ConfigurationException e) {
// some exception handling logging
}
}
// now some getters pulling data out of the config object
public static String getProperty(String fieldKeyName) {...}
public static String getColumnFamily(String fieldName) {...}
// ... some more getters
// NO setters (thus making this a read-only class)
}
Thus, basically I have for myself a Singleton class, that the very first time that it is put to use, sets up a configuration object, and then simply keeps listening for get calls. There are a number of problems with this class:
Unit testing the static methods within class HBaseUtil becomes difficult because of a tight-knit coupling between the Singleton and the configurations file.
What I really want is me being able to supply the filename/filename+path to the class so that it can go in there, read the configuration properties from that file and offer them to incoming read requests. One important note here though: I need this flexibility in specifying the properties file ONLY ONCE per JVM launch. So I certainly don't need to maintain state.
Here is what I was able to come up with:
Instead of a Singleton, I have a normal class with all static methods and no explicit constructor defined.
public class HBaseUtil {
// directly start with getters
public static String getProperty(Configuration config, String fieldKeyName) {...}
public static String getColumnFamily(Configuration config, String fieldKeyName) {...}
// ...and so on
}
And then, instead of using the class in my other code like such:
HBaseUtil.getProperty(String fieldKeyName)
I'd use it like so:
Configuration externalConfig = new PropertiesConfiguration("my-custom-hbase.properties");
HbaseUtil.getProperty(externalConfig, fieldKeyName)
My questions:
Am I even thinking in the right direction? My requirement is to have the flexibility in the class only ONCE per JVM. All that needs to be configurable in my project for this, is the location/contents of the HBase .properties file. I was thinking having a Singleton is overkill for this requirement.
What other better approaches are there for my requirement (stated in above point)?
Thanks!
Note: I've read this StackOverflow discussion, but now it's gotten me even more confused.
You should avoid all static methods and instead design a class which does not mandate its lifecycle: it can be a typical immutable POJO with a public constructor.
Then, when you need it as a singleton, use it as a singleton. For testing, use it in some other way.
Usually, dependency injection is the preferred avenue to solve these problems: instead of hard-coding a pulling mechanism for your configuration object, you have the object delivered to any class which needs it. Then you can decide late what bean you will deliver.
Since you are probably not using Spring (otherwise dependency injection would be your default), consider using Guice, which is a very lightweight and non-intrusive approach to dependency injection.
I have been using Guice for a few years now and just switched to a company that uses Spring. I am a fan of Dependency Injection but having a few issues figuring out how to get Spring to do what I want.
Here is what I have in the code right now (its not scala code, just shorter so using that syntax):
class A(b: B)
class B(exe: ExecutorService)
...
#Value("${search.threads}") var searchThreads: int
exe = Executors.newFixedThreadPool(searchThreads)
In guava I could use Named annotations to have different executors, or just use one executor for anyone that needed it and just define
final int searchThreads = readSearchThreadsFromConfigs()
bind(Executor.class).toInstance(Executors.newFixedThreadPool(searchThreads));
I am not sure how to set this up within Spring. It seems every example I see doesn't really cover generics, nor does it really go over static constructors or being able to "provide" the value.
What is the best way to get similar results to what I had above from Guice? Is there a notion of a "module" like guice and dagger use (other than the xml file, something statically checked)?
EDIT:
Here is a bit of the code currently used. It creates the executor within the constructor:
#Autowired
public LogsModule(#Value("${search.threads}") final int searchThreads) {
searchPool = Executors.newFixedThreadPool(searchThreads);
}
In Spring it's basically the same.
Your example can be rewritten as follows using #Configuration:
#Bean(value = "searchExecutor", destroyMethod = "shutdownNow")
public ExecutorService executorService(Environment env) {
final int searchThreads = env.getProperty("searchThreads", Integer.class, 3);
return Executors.newFixedThreadPool(searchThreads));
}
This example uses Environment - you can either add properties from your config to it, or use your config directly instead.
With XML configuration it would be more complex, but you can mix #Configuration with XML.
If you need multiple executors, you can use #Qualifier (or perhaps #Named) to distinguish between candidates by their bean names:
#Autowired
public LogsModule(#Qualifier("searchExecutor") ExecutorService e) { ... }
I have an API which I am turning into an internal DSL. As such, most methods in my PoJos return a reference to this so that I can chain methods together declaratively as such (syntactic sugar).
myComponent
.setID("MyId")
.setProperty("One")
.setProperty2("Two")
.setAssociation(anotherComponent)
.execute();
My API does not depend on Spring but I wish to make it 'Spring-Friendly' by being PoJo friendly with zero argument constructors, getters and setters. The problem is that Spring seems to not detect my setter methods when I have a non-void return type.
The return type of this is very convenient when chaining together my commands so I don't want to destroy my programmatic API just be to compatible with Spring injection.
Is there a setting in Spring to allow me to use non-void setters?
Chris
Thanks to all (and especially Espen who went to a lot of effort to show me the various options within Spring).
In the end, I found a solution myself that doesn't require Spring configuration.
I followed the link from Stephen C then found a reference to the SimpleBeanInfo class within that set of Threads. This class allows a user to write their own bean method resolution code by placing another class in the same package as the class with the non-standard setters/getters to override the logic of with 'BeanInfo' appended onto the classname and implementing the 'BeanInfo' interface.
I then did a search on Google and found this blog which pointed the way. The solution on the blog was quite basic so I padded it out for my purposes.
Per Class (with fluent setters)
public class MyComponentBeanInfo<T> extends SimpleBeanInfo {
private final static Class<?> _clazz = MyComponent.class;
PropertyDescriptor[] _properties = null;
public synchronized PropertyDescriptor[] getPropertyDescriptors() {
if (_properties == null) {
_properties = Helpers.getPropertyDescriptionsIncludingFluentSetters(_clazz);
}
return _properties;
}
public BeanDescriptor getBeanDescriptor() {
return new BeanDescriptor(_clazz);
}
}
PropertyDescriptor generation method
public static PropertyDescriptor[] getPropertyDescriptionsIncludingFluentSetters( Class<?> clazz) {
Map<String,Method> getterMethodMap = new HashMap<String,Method>();
Map<String,Method> setterMethodMap = new HashMap<String,Method>();
Set<String> allProperties = new HashSet<String>();
PropertyDescriptor[] properties = null;
try {
Method[] methods = clazz.getMethods();
for (Method m : methods) {
String name = m.getName();
boolean isSetter = m.getParameterTypes().length == 1 && name.length() > 3 && name.substring(0,3).equals("set") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';
boolean isGetter = (!isSetter) && m.getParameterTypes().length == 0 && name.length() > 3 && name.substring(0,3).equals("get") && name.charAt(3) >= 'A' && name.charAt(3) <= 'Z';
if (isSetter || isGetter) {
name = name.substring(3);
name = name.length() > 1
? name.substring(0,1).toLowerCase() + name.substring(1)
: name.toLowerCase();
if (isSetter) {
setterMethodMap.put(name, m);
} else {
getterMethodMap.put(name, m);
}
allProperties.add(name);
}
}
properties = new PropertyDescriptor[allProperties.size()];
Iterator<String> iterator = allProperties.iterator();
for (int i=0; i < allProperties.size(); i++) {
String propertyName = iterator.next();
Method readMethod = getterMethodMap.get(propertyName);
Method writeMethod = setterMethodMap.get(propertyName);
properties[i] = new PropertyDescriptor(propertyName, readMethod, writeMethod);
}
} catch (IntrospectionException e) {
throw new RuntimeException(e.toString(), e);
}
return properties;
}
Advantages to this approach:
No custom spring configuration (Spring is not aware of the non-standard setters and sees them as normal). No dependancy on any Spring .jar files but accessible from Spring.
Just seems to work.
Disadvantages to this approach:
I have to place create a BeanInfo class for all of my API classes with non-standard setters. Luckily there are only around 10 such classes and by moving the method resolution logic into a seperate class I only have one place to maintain.
Closing Thoughts
In my opinion, Spring should deal with fluent setters natively, they don't hurt anyone and it should just ignore the return value.
By requiring that setters be rigidly void, it has forced me to write a lot more boiler plate code than I would have needed otherwise. I appreciate the Bean Specification, but bean resolution is trivial using reflection without even using the standard bean resolver so Spring should offer the option of its own bean resolver that will handle this situations.
By all means, leave the standard mechanism as the default, but offer a one-line configuration option. I look forward to future versions where this might be optionally relaxed.
Is there a setting in Spring to allow me to use non-void setters?
The simple answer is No - there is no such setting.
Spring is designed to be compatible with the JavaBeans spec, and that requires the setters to return void.
For a discussion, refer to this Spring Forums thread. There are possible ways around this limitation mentioned in the forum, but there is no simple solution, and I don't think anyone actually reported that they had tried this and that it worked.
Spring can also be configured with Java configuration.
An example:
#Configuration
public class Config {
#Bean
public MyComponent myComponent() {
return MyComponent
.setID(id)
.setProperty("One", "1")
.setProperty("Two", "2")
.setAssociation(anotherConfig.anotherComponent())
.execute();
}
#Autowired
private AnotherConfig anotherConfig;
#Value("${id}")
private String id;
}
You have a nice immutable object. You have actually implemented the Builder pattern!
Updated to respond to Chris's comment:
I guess it's not exactly what you want, but using properties files solves some issues. See the id field in the example above.
Else, you can use Spring's FactoryBean pattern:
public class MyComponentFactory implements FactoryBean<MyComponent> {
private MyComponent myComponent;
public MyComponentFactory(String id, Property propertyOne, ..) {
myComponent = MyComponent
.setID(id)
.setProperty("One", "1")
.set(..)
.execute();
}
public MyComponent getObject() throws Exception {
return myComponent;
}
public Class<MyComponent> getObjectType() {
return MyComponent.class;
}
public boolean isSingleton() {
return false;
}
}
With the FactoryBean, you shield the configuration from the object returned from the getObject() method.
In the XML configuration, you configure the FactoryBean implementation. In this case with <constructor-arg /> elements.
One simple suggestion, it is customary not to use setters, but the properties names themselves. So have a setter, and have another method for the builder:
component.id("MyId")
.property("One")
.property2("Two")
.association(anotherComponent)
.execute();
As far as I know, there is no simple switch. Spring uses the Beans convention, and expects a void setter. Spring works with beans at the property level via an instance of the BeanWrapper interface. The default implementation, BeanWrapperImpl, uses introspection, but you could create your own modified version that uses reflection to find methods matching your pattern.
EDIT: Looking at the Spring code, BeanWrapperImpl is hard-wired into the bean factories, there is no simple way to replace this with another implementation. However, as spring uses introspection, we can work on getting java.beans.Introspector to produce the results we want. Here are the alternatives in order of decreasing pain:
change the method signature on your setters to comply.
implement your own BeanInfo classes for each of your beans
Use reflection to plug dynamically generated BeanInfo classes into the introspector.
The first two options are probably not really options for you, as they involve quite a lot of changes. Exploring the third option in more detail:
To know which beans are being instantiated by spring, implement your own BeanFactoryPostProcessor. This gets to see all the bean definitions before they are used by the BeanFactory. Your implementation iterates over all the BeanDefinitions in the factor, and fetches the bean class from each definition. Now you know all the classes that are being used.
With a list of classes, you can set about creating your own BeanInfos for these classes. You use the Introspector to generate the default BeanInfo for each class, which would give you read-only properties for your properties with return value setters. You then create a new BeanInfo, based on the original, but with PropertyDescriptors referencing setter methods - your return value setters.
With new beanInfos generated for each class, you need to make sure that the Introspector returns these when asked for the beaninfo for your class. The introspector has a private Map that is used to cache beanInfos. You can get hold of this via reflection, enable access - setAccessible(true) - and add your BeanInfo instances to it - map.put(Class,BeanInfo).
When spring asks the Introspector for the BeanInfo for your bean class, the introspector returns your modified beanInfo, complete with setter methods mapped to your setters with return values.
As others have said, it's not just Spring-friendliness you risk losing. A non-void setter isn't really a setter as far as JavaBeans are concerned, and all sorts of other tools (validators, marshallers, viewers, persisters, whatever else you can dream up) will probably use Introspector and BeanInfo, which expect setters to be null.
With this in mind, how flexible is the requirement that they be called setX? A lot of fluent interfaces in Java use withX instead. If you're using Eclipse, you can probably create a code generation template to make X getX(), void setX(X x), and X withX(X x) for you. If you're using some other codegen tool, I can imagine adding withX fluent setter/getter methods would also be easy.
The with word seems a bit odd, but when you see it alongside a constructor it reads really well.
Request r = new Request().withEndpoint("example.com")
.withPort(80)
.withSSL(false)
.withFoo("My Foo");
service.send(r);
One such API is the AWS SDK for Java, which you can consult for examples. An off-topic caveat is that boolean getters may be called isX, but Boolean getters must be called getX.