How to inject values from another properties file into ValidationMessages.properties? - java

I need to change the #NotNull message used by hibernate-validator.
Have successfully done this using a line in ValidationMessages.properties, e.g: javax.validation.constraints.NotNull.message=my validation message.
However, this isn't quite what's needed. Will spare the details about why but all these messages should originate from a single messages.properties file, whose purpose is not only for validation but other messages as well.
Let's say messages.properties initially contains a single property CCCI_0001=my generic message. Is it possible to somehow substitute this property value from messages.properties into a placeholder in ValidationMessages.properties?

What you can do is bootstrap your ValidatorFactory with a custom MessageInterpolator. If you are happy to use a Hibernate Validator specific feature, you can use a ResourceBundleLocator - see http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-custom-message-interpolation. It looks somewhat like this:
Validator validator = Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new PlatformResourceBundleLocator( "MyMessages" )
)
)
.buildValidatorFactory()
.getValidator();

Related

To provide nicer logging when a Spring property is invalid

Using a application.properties file my Spring Boot app can use some property values in it. A way to make sure a mandatory value must present is to add an annotation #Value for the property. The problem with this is the app fails miserably if the property value is not there in the properties file.
I am after a nicer less horrible way to say printing out a log line about "Property A is missing" instead of a whole stack trace. Is there a way to do this while still using #Value to initialise the properties? For example, property A is mandatory, an error is logged before app exits; property B is missing but not mandatory, a warning is logged and app continues.
If you can identify all property, then you can write a method in Application class with #Postconstruct, and inside your method, you can manually validate and log them
#Autowired
private Environment environment;
#PostConstruct
private void validateProperties() {
environment.getProperty(key);
.....
......
}
Alternatively, you can write your custom EnvironmentPostProcessor, and iterate all properties and log whichever is null/empty.
As you're using spring-boot consider creating a #ConfigurationProperties class rather than using the #Value annotation.
By doing that you can do your validations using Bean Validation, also in the same class, you can implement the interface InitializingBean and add extra validations/log messages as you with.
Follow this link on Spring's official docs to read more about #ConfigurationProperties.

What does getBean() method do here?

What is the getBean() method doing here and how does it work in a program?
ApplicationContext aplicntxt = new
ClassPathXmlApplicationContext("springconfig.xml");
Hello h = (Hello) aplicntxt.getBean("springconfig.xml");
h.display();
Hello h2 = new Hello(); //if I write this
h2.display();
My question is why h2.display retrieves null value and h.display retrieves the stored values through springconfig.xml?
Please tell me what does
ApplicationContext aplicntxt = new ClassPathXmlApplicationContext("springconfig.xml");
do first?
Are all the values of xml file stored to the pojo class setters at first step?
Then we are storing the values to an object h
by doing
Hello h = (Hello) aplicntxt.getBean("springconfig.xml");
Your question is essentially "How does spring work", this is covered extensively by the official documentation
The following creates all the beans defined by the springconfig.xml, that is it creates objects of the given types, and injects any properties you've defined, depending on your exact configuration it may also do things like package scanning, annotation processing etc.
ApplicationContext aplicntxt= new ClassPathXmlApplicationContext("springconfig.xml");
XML
<bean class="org.example.Hello" id="foo" />
<bean class="org.example.Hello" id="bar" />
This would create an objects of type Hello and tag them with the IDs "foo" and "bar"
All the beans are stored against their IDs for later retrieval via getBean(), note this takes the bean ID or name, not the XML file.
Hello h = (Hello) aplicntxt.getBean("foo");
What you are doing in code is called Spring Dependency Injection which let you define application beans and inject them when you need. like getBean() method that you use in your code which inject specific bean from XML file.
From spring doc
The interface org.springframework.context.ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It allows you to express the objects that compose your application and the rich interdependencies between such objects.
Several implementations of the ApplicationContext interface are supplied out-of-the-box with Spring. In standalone applications it is common to create an instance of ClassPathXmlApplicationContext or FileSystemXmlApplicationContext. While XML has been the traditional format for defining configuration metadata you can instruct the container to use Java annotations or code as the metadata format by providing a small amount of XML configuration to declaratively enable support for these additional metadata formats.
Now Your Question and its simple ApplicationContext activates the object(it is eager container) and looks for the beans declared so the objects are loaded whenever it is called.
Now consider if you have two beans , and you need one of them you will find that bean by using ctx.getBean("beanId") to load instance and to provide data declared with this bean where beanId will tell which object to load.
consider following example
<bean id="a" class="package.Hello" />
//here it will look for bean name and then loads the class
Now when You call it like
ApplicationContext ctx=new ClassPathXMLApplicationContext("configuration.xml");
//will look for configuration.xml bean file if it is not in path then throw execption.
now
Hello hello=ctx.getBean("a");
// if configuration.xml contains any bean named "a" and holds reference to class(hello) load it immediately and return object of that class
is same as
Hello hello=new Hello();
hello.method();
and it is creating object of Hello class by using xml
From looking at this quickly, it appears that this code uses spring to initialize the Hello object with the values specified in the spring bean found in the xml file (I'm assuming that's what's in the filr, but I could be more specific if you post it).. When you create a second hello object you are using the constructor's default value for display, which is null.

Is Spring's #Value annotation part of internationalization?

I am working on a project where internationalized messages are retrieved using the #Value annotation.
e.g.:
#Value("${email.newUser.subject}")
private String NEW_USER_SUBJECT;
#Value("${email.newUser.message}")
private String NEW_USER_MESSAGE;
However, as part of my investigation, it appears that the #Value annotation is used to get a property from a property file and does not link into to automatic lookup of the correct version of the message.properties. Therefore as I understand it, this is only working by coincidence because we have currently only a single message.properties file.
Can anyone in the know tell me if I have the correct understanding of the situation?
The Answer is No, the #Value annotation is not part of Internationalization. It's use in conjunction with Internationalization is an error and will break when you try to change the Local.

Configure JSR-303 hibernate validator with different mappings

I'm looking into using JSR-303 with hibernate validator. We would like to be able to have different validations per each customer or have a base set of constraints and allow them to be overridden.
I'm not sure what's the best way to do this.
Using annotations for constraints is not suitable since they're essentially hard-coded in the models. I know I can use XML to externalize the validations (creating META-INF/validation.xml which specifies constraint-mapping files). But I'm not really sure how to easily make this configurable for multiple customers.
I suppose I would like to be able to set a simple property so that when we deploy it uses a completely different set of constraint-mapping files.
Any ideas?
You could create a ValidatorFactory per customer which you configure with customer-specific constraint mapping XML files like this:
ValidatorFactory validatorFactory = Validation
.byDefaultProvider()
.configure()
.addMapping(...) //input stream with an XML constraint mapping
.addMapping(...) //another input stream with an XML constraint mapping
.buildValidatorFactory();
When you're working with Hibernate Validator, you could also use the API for programmatic constraint declaration to create individually configured validator factories.

How to load/access a bean (#Resource) in a custom Velocity tool

I realize this is a slightly funky thing to need to do, but I'm trying to access my Spring messageSource bean from a custom Velocity tool.
In most of our codebase, I'm able to just set up a member variable and load it like this:
#Resource(name = "messageSource")
private AbstractMessageSource _msgSource;
However, in this circumstance, this doesn't load the bean, I'm assuming because the Velocity tools get instantiated in a way that doesn't allow normal bean loading to occur. Or it doesn't want to initialize the bean for an application scoped Velocity tool.
The tool is set up in the toolbox.xml as follows:
<tool>
<key>calendarTool</key>
<scope>application</scope>
<class>...</class>
</tool>
I haven't been able to find anything online that explains either how to do this or why it doesn't work.
What I've done is in the code where I render the Velocity template, I retrieve the message source from the applicationContext using applicationContext.getBean("messageSource") and then I put that MessageSource directly into the the VelocityContext that I use to render my templates under the key "messageSource" :
VelocityContext velocityContext = new VelocityContext();
velocityContext.put("messageSource", applicationContext.getBean("messageSource"));
Then, anytime I want to render a message key, say in an HTML email, it looks something like :
<td>messageSource.getMessage("my.message.key", null, $locale)</td>
where $locale is a java.util.Locale object that I've also manually placed in the VelocityContext. If I ever need any arguments to the message, then I use the list tool I've put in the context to get an array from the list of arguments I'll typically create right there in the template. As a side note, you can use the helper methods in the
org.springframework.ui.velocity.VelocityEngineUtils class to help you out with rendering Velocity templates in your controllers or webflow code, or wherever else you may be rendering templates.
Not sure why it doesn't work, but have you tried retrieving it without annotations, something like:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
AbstractMessageSource _msgSource = (AbstractMessageSource )ctx.getBean("messageSource");

Categories

Resources