Not sure of the best approach to this. We've created a jar that could be used by different projects. The other projects relying on this jar need to provide certain properties defined in one of their spring properties files. (Our jar shouldn't care what they name those property files.)
Using #Value("${some.prop}") works great for most properties, however we now have the requirement that the name of the property to look up is dynamic. For example:
int val = getSomeVal();
String propNeeded = foo.getProperty("foo."+val+".dynamic.prop");
Not sure what "foo" should be to get my access. I looked into injecting Environment, however from all my googling it looks like that will not load from an xml property-placeholder definition (even if defined as a bean def for PropertySourcesPlaceholderConfigurer.) You seem to have to use #PropertySource, yet my main config is an XML file so not sure how to get Environment to work. (I can't really go 'old skool' and look up the property file as a class path Resource either since I'm not aware of the name of the file the users defined.)
I don't mind making this particular Service class ApplicationContextAware, but if I did that how could I get access to the underlying PropertySourcesPlaceholderConfigurer ? which I would 'seem?' to need in order to get access to a property dynamically?
The other option is that I force users of the jar to declare a bean by a name that I can look up
<util:properties id="appProps" location="classpath:application.properties" />
And I then inject appProps as Properties and look up from there. I don't like this approach though since it forces the users of the library to name an file by a common id. I would think the best solution is to just get a handle in some way to the underlying PropertySourcesPlaceholderConfigurer in my service class... I'm just not sure how to do it?
Why doesn't Spring simply allow PropertySource to be defined some how via your XML config and then I could just inject Environment?
Thanks for any suggestions how to accomplish what I want.
You could have a ReloadableResourceBundleMessageSource declared to read from the same source as the PropertySourcesPlaceholderConfigurer. This way you could just #Autowire MessageSource (or make your bean implement MessageSourceAware) and use that to retrieve your properties.
Main reason for using ReloadableResourceBundleMessageSource is to retrieve I18N messages, so that would kind of hacky...
Related
I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties
I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).
We're building a Spring-based application which will be delivered to end users as a distribution package. Users are responsible for properly configuring whatever needs to be configured (it's mostly about various filesystem locations, folder access permissions, etc). There's a good idea to make the app help users understand what is not configured or which parts of configuration are invalid.
Our current approach is a custom ApplicationContextInitializer which does all the environment validation "manually" and then registers few "low level" beans in the application context explicitly. If something is wrong, initializer throws, exception is caught somewhere in main(), interpreted (converted into plain English) and then displayed.
While this approach works fine, I'm wondering if there are any best practices to minimize hand-written code and use Spring whenever possible.
Here's an illustrative example. The application requires a folder for file uploads. This means:
There should be a configuration file
This file should be accessible by the app
This file should have no syntax errors
This file should explicitly define some specific property (let it be app.uploads.folder)
This property should describe the existing filesystem entity
This entity should be a folder
The app should have read/write access to this folder
Does Spring provide any tools to implement this sort of validation easily?
Spring Boot has a nice feature for context and external configuration validation. If you define a POJO class and declare it as #ConfigurationProperties then Spring will bind the Environment (external properties and System/OS typically) to its properties using a DataBinder. E.g.
#ConfigurationProperties(name="app.uploads")
public class FileUploadProperties {
private File folder;
// getters and setters ommitted
}
will bind to app.uploads.folder and ensure that it is a File. For extra validation you can do it manually in the setter, or you can implement Validator in your FileUploadProperties or you can use JSR-303 annotations on the fields. By default an external property in app.uploads.* that doesn't bind will throw an exception (e.g. a mis-spelled property name, or a conversion/format error).
If you use Spring Boot Autoconfigure #EnableAutoConfigure you don't have to do anything else, but if it's just vanilla Spring (Boot) you need to say #EnableConfigurationProperties in your #Configuration somewhere as well.
A bonus feature: if you also use the Spring Boot Actuator you will also get JMX and HTTP support (in a webapp) for inspecting the bindable and bound properties of #ConfigurationProperties beans. The HTTP endpoint is "/configprops".
Looking for a solution that will provide us more functionality within Spring properties such as:
nested structures
maps/lists
properties referencing other properties. Example:
city.name=Toronto
city.address=#{city.name}, 123 Ave SW
I tried EProperties (Google) and Commons Configurations (Apache) but doesn't seem to integrate very well with the Spring Framework.
Also, we're using Velocity to access properties using #springMessage("city.address"), so it needs to work for that.
Does anyone know how I can achieve the above by extending the default Properties capability?
With newest versions of Spring you can use the PropertySource mechanism. You register all your PropertySource and the order in which they are searched and then you don't have to do anything, except perhaps add this to your XML:
<context:property-placeholder />
As long as you declare only one of these without specifying local property files (the "old way"), you will be able to reference property A as the value of property B, even if they are not in the same property source.
For nested structures this may help if you don't like the properties readability:
https://stackoverflow.com/a/13470704/82609
For parsing problems you can easily handle lists and other stuff like that manually very easily:
Reading a List from properties file and load with spring annotation #Value
I am confused on the usage of alias. I do understand what alias is and how it is being used but i don't see how it can be any different than using names on a bean definition.
<bean id="xyx" name="abc,def" .. />
<alias name="xyx" alias="pqr"/>
Why the alias when i can use abc or def?
In my mind bean aliasing can be helpful in large system, where you can not manipulate bean names. You have option to create your own name (alias) specific for your part of the system...
from Spring documentation (3.0.x)
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/
...it is sometimes desirable to give a single bean multiple names,
otherwise known as bean aliasing...
therefore creating multiple names or/and aliasing are the same thing.
A use case maybe when you want to customize some beans that are already defined somewhere in a modular application (each module is a spring project for example), the bean maybe defined by a third-party framework/API or even your team. In that case you want that only inside your spring project call the customized version without altering other modules (projects), to do that just add the alias in your spring configuration which is indeed a powerful feature:
<alias alias="globalBeanService" name="customizedBeanService" />
Hence, whenever spring find a call to the globalBeanService, it will inject customizedBeanService for you inside your specific module.
Without this feature, you should go through all classes and modify the bean manually!!
An aliased bean will always have higher priority over a non-aliased one, and in case of having different beans with the same alias then the last one declared will have the priority. In other words, the aliased bean will override the non-aliased beans.
This can be particularly useful when creating big projects or when you are building extensions to your project and don't want to touch the original bean definition.
Alias has a specific using scenario which multiple names don't have:
Imagine multiple config xml files in your project, most of which are authored by your colleagues, and you need to add your own config.xml file. Using you'll be able to refer to a bean defined in another config file with a different name that's maybe more meaningful to your config, without having to touch your colleagues' config files.
I recently found another use case where alias easily solved a problem.
When auto configuration is active, Spring Boot provides the bean serverProperties which can be used to access information about the server currently running the web app.
In integration tests (i.e. when #SpringBootTest annotation is present) the same bean is available under the name org.springframework.boot.autoconfigure.web.ServerProperties.
Of course it is possible to use a different profile for integration testing, but that would require manual change of configuration at multiple places. However, simply by adding
<alias name="serverProperties" alias="org.springframework.boot.autoconfigure.web.ServerProperties"/>
the same configuration files can be used for integration tests and in production.
This might be a bug in Spring Boot, however alias easily solve the problem without waiting for a new release. And most certainly I have no possibility to alter the Boot configuration myself.