Spring boot configuration properties validation not working - spring-boot

Trying to implement configuration properties validation for immutable beans as described in Spring boot docs:
#Validated
#ConstructorBinding
I'm using Spring boot 2.4.0.
Sample immutable properties class:
#Validated
#ConstructorBinding
#ConfigurationProperties("prefix")
public class Props {
private final String suffix;
public Props(#NotBlank String suffix) {
this.suffix = suffix;
}
public String getSuffix() {
return suffix;
}
#Override
public String toString() {
return "Props [suffix=" + suffix + "]";
}
}
For a test, I did this:
System.setProperty("prefix.suffix", "value");
and I get the correct binding, i.e.:
Props [suffix=value]
However, by making a typo in the property name (added 1 to the property name):
System.setProperty("prefix.suffix1", "value");
I get this:
Props [suffix=null]
I see validation activated in the logs:
HV000001: Hibernate Validator 6.1.6.Final
Form their docs, it is supposed to do constructor parameter validation:
As of Bean Validation 1.1, constraints can not only be applied to JavaBeans and their properties, but also to the parameters and return values of the methods and constructors of any Java type.
Why is #NotBlank (full import: import javax.validation.constraints.NotBlank;) not causing validation exceptions?

Related

#Value annotation unable to read properties file in spring boot camel application

I have a spring-boot application where I read data from queue and send data to transformation class using .bean()
Integration.java
class Integration {
#Value("${someURL}")
private String someURL; //able to read someURL from property file
from("queue")
// some intermediate code
.bean(new TransformationClass(), "transformationMethod")
// other code
}
Now, Inside TransformationClass I have #Value annotation to read values from properties file but it always returns a null.
TransformationClass.java
#Component
class TransformationClass {
#Value("${someURL}")
private String someURL; //someURL return null though there is key-value associated in props file.
public void transformationMethod(Exchange exchange) {
// other stuff related to someURL
}
}
Note - I am able to read values from property file in class Integration.java but unable to read from class TransformationClass.java
I am using spring boot version - 2.7.2 and camel version - 3.18.1 jdk - 17
I tried to read using camel PropertiesComponent but it did not worked.
Problem here is, that new TransformationClass() is not a "spring managed instance", thus all #Autowire/Value/Inject/...s have no effect.
Since TransformationClass is (singleton, spring-managed) #Component and is needed by Integration, wiring these makes sense:
Via field... :
class Integration {
#Autowired
private TransformationClass trnsObject;
// ...
Or constructor injection:
class Integration {
private final TransformationClass trnsObject;
public Integration(/*im- /explicitely #Autowired*/ TransformationClass pTrnsObject) {
trnsObject = pTrnsObject;
}
// ...
// then:
doSomethingWith(trnsObject); // has correct #Values
}

Spring #Value not working in Spring Boot 2.5.5, getting null values

I am trying to inject some property values into variables by means of Spring #Value annotation but I get null values. I tried different configurations and triks but it doesn't work. Think is that before today everythink was working properly. I do not know what I changed in order to get things broken.
Here is my java class:
#Component
#ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {
#Value("${studioghibli.basepath}")
private static String BASE_PATH;
#Value("${studioghibli.path}")
private static String PATH;
#Value("${studioghibli.protocol:http}")
private static String PROTOCOL;
#Value("${studioghibli.host}")
private static String HOST;
private static String BASE_URI = PROTOCOL.concat("://").concat(HOST).concat(BASE_PATH).concat(PATH);
#Autowired
StudioGhibliRestConnector connector;
public List<StudioGhibliFilmDTO> findAllFilms() throws SipadContenziosoInternalException {
var response = connector.doGet(BASE_URI, null, null);
if (!response.getStatusCode().is2xxSuccessful() || !response.hasBody()) {
throw new SipadContenziosoInternalException(Errore.INTERNAL_REST_ERROR, "FindAll(), microservizio ".concat(BASE_URI), null);
}
return (List<StudioGhibliFilmDTO>) response.getBody();
}
}
As you can see, the class is annotated with #Component, that because I will need to use it as #Service layer in order to make a rest call in my business logic.
The class is also annotaded with conditional on property...
Here is a screenshot of the debug window at startup:
Since the PROTOCOL value is null, i get a null pointer exception immediately at start up.
Here is part of the application-dev.properties file:
studioghibli.get
studioghibli.protocol=https
studioghibli.host=ghibliapi.herokuapp.com
studioghibli.basepath=/
studioghibli.path=/films
First of all, #Value annotation does not work with static fields.
Secondly, fields with #Value annotation is processed when the instance of the class (a bean) is created by Spring, but static fields exist for a class (for any instance), so when the compiler is trying to define your static BASE_URI field other fields are not defined yet, so you get the NPE on startup.
So you might need a refactoring, try to inject values with the constructor like this:
#Component
#ConditionalOnProperty(prefix = "studioghibli", name = "get")
public class StudioGhibliRestService {
private final StudioGhibliRestConnector connector;
private final String baseUri;
public StudioGhibliRestService(StudioGhibliRestConnector connector,
#Value("${studioghibli.basepath}") String basePath,
#Value("${studioghibli.path}") String path,
#Value("${studioghibli.protocol:http}") String protocol,
#Value("${studioghibli.host}") String host) {
this.connector = connector;
this.baseUri = protocol.concat("://").concat(host).concat(basePath).concat(path);
}
// other code
}
Thanks, It works for me, I have to add some codes to my project. Then I check the spring core document in "#Value" section. Besides
When configuring a PropertySourcesPlaceholderConfigurer using
JavaConfig, the #Bean method must be static.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}

Expose public field of POJO to FTL in Spring

I can't figure out how to send a POJO to my template in Spring Boot.
Here's my POJO and my controller:
class DebugTest {
public String field = "Wooowee";
public String toString() {
return "testie " + field;
}
}
#Controller
#RequestMapping("/debug")
public class WebDebugController {
#RequestMapping(value = "/ftl", method = RequestMethod.GET)
public ModelAndView ftlTestPage(Model model) {
DebugTest test = new DebugTest();
ModelAndView mnv = new ModelAndView("debug");
mnv.addObject("test", test);
return mnv;
}
}
Here's my template:
HERES THE TEST: ${test}$
HERES THE TEST FIELD: ${test.field}$
Here's the output (GET /debug/ftl):
HERES THE TEST: testie Wooowee$
HERES THE TEST FIELD: FreeMarker template error (DEBUG mode; use RETHROW in production!):
The following has evaluated to null or missing:
==> test.field [in template "debug.ftl" at line 3, column 25]
[Java stack trace]
The class itself (DebugTest) must be public too, as per the JavaBeans Specification. Also, fields by default aren't exposed. Defining getter methods is generally the best (with Lombok maybe), but if you want to go with fields, configure the ObjectWrapper as such. As you are using Spring Boot, I think that will be something like this in your application.properites:
spring.freemarker.settings.objectWrapper=DefaultObjectWrapper(2.3.28, exposeFields = true)

#Value In Spring MVC is not getting populated

I am trying to populate an attribute using the #Value annotation in Spring MVC, and it is not getting populated.
I am trying to access the attribute using Struts2 JSP property. my use case looks like that:
public class TransferCreditsAction extends StudentAwareAction {
protected Log logger = LogFactory.getLog(this.getClass());
#Value( "${transfer.credit.url}" )
private String transferCreditUrl;
public void setStates( List<TranslatedValue> states ) {
this.states = states;
}
#Value( "${transfer.credit.url}" )
public String getTransferCreditUrl() {
return transferCreditUrl;
}
}
My property file looks like:
transfer.credit.url
I am accessing this attribute using JSP which looks like:
<s:property value='transferCreditUrl'/>"
I know for a fact that my JSP can access this field, because I tested it when I have this field set for a default value.
However, this field is not getting populated from my property file. I am using Spring 4.1.6
Any help is really appreciated.
Spring can only inject values in its own managed spring beans. That means your TransferCreditsAction should be a spring bean.
There are various ways to declare your TransferCreditsAction class as a spring bean, already answered elsewhere.
You haven't added whats on top of TransferCreditsAction class.
Values will be injected in a Bean Env.
There are many ways of Doing it
Assuming my property file contains
username=Ashish
app.name=Hello
1.
#Service
#PropertySource(value = { "classpath:sample.properties" })
public class PaloAltoSbiClientImpl implements PaloAltoSbiClient {
public static String username;
#Value("${username}")
public void setUrl(String data) {
username = data;
}
...
2.
#Service
public class PaloAltoSbiClientImpl implements PaloAltoSbiClient {
#Value("${username}")
public static String username;
...
3.
#Component
public class TokenHelper {
#Value("${app.name}")
private String APP_NAME;
Just give the properties file reference on top of the class in which you are trying to get.
#PropertySource(value = { "classpath:sample.properties" })
This issue was happening because I was missing <context:annotation-config/> in my applicationContext. Once I added it, it start working with no issues.

How to inject values to a wicket page using spring?

Is it possible to inject a value to a wicket page using spring?
With #Value it's possible to inject values to a spring bean.
I know the #SpringBean annotation, but this is only for beans.
My workaround is to wrap the value with a spring bean and then inject this with #SpringBean to my wicket page. Is there a better way to do this?
We have solved this problem using getter & setter in our custom child of WebApplication. This child is standard Spring bean and is configured in spring's configuration.
Otherwise you have to create some "config" bean.
You can write a Wicket resource loader to load spring values, and then those values will be resolved like regular wicket messages. If instead you need it within the body of the wicket class to do some business logic, that may be an opportunity to refactor that logic outside of the view layer.
Here's what the resource loader looks like:
public class SpringPropertiesResourceLoader
implements IStringResourceLoader
{
public SpringPropertiesResourceLoader()
{
}
#Override
public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, String variation)
{
return loadStringResource(key);
}
#Override
public String loadStringResource(Component component, String key, Locale locale, String style, String variation)
{
return loadStringResource(key);
}
private String loadStringResource(String key)
{
try
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(WebPortalApplication.get().getServletContext());
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
String rv = beanFactory.resolveEmbeddedValue("${" + key + "}");
return rv;
}
catch (IllegalArgumentException iae)
{
// no property with the name - move along
return null;
}
}
}
Then add that to your application in init():
getResourceSettings().getStringResourceLoaders().add(new SpringPropertiesResourceLoader());

Resources