Access Spring Boot Actuator build.version property with #Value - java

THis should be easy, but doesn't work.
I have spring-boot-actuator activated in my Spring Boot (2.0.1-RELEASE) application.
The Actuator-Endpoint /actuator/info works as expected and also shows the correct version info. The file build-info.properties is present.
When trying to access the version property with (e.g. in my Spring-Controller-Class):
#Value("${build.version}) private String version;
The action fails with the error Could not resolve placeholder 'build.version' in value "${build.version}".
ANy suggestions?

With spring expression language it is pretty simple and clean.
#Value("#{buildProperties.get('version')}") // not 'build.version'
private String myAppBuildVersion;
Or better, Autowire the buildProperties bean directly to your components so you can play with it as you want.
#Autowired
private BuildProperties buildProperties;
NOTE: The autoconfiguration strips off the build. prefix. So your
SpEL expressions should use version as key. Not build.version.

I needed to add the file build-info.properties as #PropertSource
#SpringBootApplication()
#PropertySource("classpath:META-INF/build-info.properties")
public class MyApp implements WebMvcConfigurer {
[...]
}
Then you can use the build-info in annotations
#SomeAnnotation(value = "${build.version}")
public class someClass { ... }

In your #Service, put the #Value in the constructor, as a parameter of the constructor. Don't use a standalone value and try to reference it.
like this:
#Service
public class myService {
public myService(#Value("${my.param}") String myParam) {
client.withParam(myParam).build();
}
}
Where your application.properties has a value like:
my.param=http://google.com
I have tried other implementations and they do not work. for example,
#Service
public class myService {
#Value("${my.param}")
String myParam;
public myService() {
client.withParam(myParam).build();
}
}
Does not work.
In this case, the service will be initialized, but the string will be null. I can't explain it. Something to do with param construction and bean initialization timing, I guess.

Related

Spring Boot: The bean 'auditLogDao' could not be injected as a 'AuditLogDao' because it is a JDK dynamic proxy

I am getting the following error in a Spring Boot project on which I work:
The bean 'auditLogDao' could not be injected as a '{redactedpathwithcorporatename}.AuditLogDao' because it is a JDK dynamic proxy that implements:
org.springframework.data.jpa.repository.JpaRepository
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
I have tried a variety of solutions on StackOverflow without success, specifically:
Checking that I am indeed calling the interface, not the implementation.
Adding #Component to the top of SwitchUserFilter
Changing #Resource to #Autowired.
AuditLogDao.java
public interface AuditLogDao extends JpaRepository<AuditLog, String> {}
AuditLogService.java
public interface AuditLogService {
AuditLog save(final AuditLog auditLog);
}
AuditLogServiceImplementation.java
public class AuditLogServiceImplementation implements AuditLogService{
#Resource private AuditLogDao auditLogDao;
#Override
public AuditLog save(AuditLog auditLog) {
return auditLogDao.save(auditLog);
}
}
The file where I actually want to use the service to save information
SwitchuserFilter.java
public class SwitchUserFilter
extends org.springframework.security.web.authentication.switchuser.SwitchUserFilter {
#Resource AuditLogService logService;
'''
logService.save(auditLog);
'''
}
I am relatively new to Spring Boot, so an explanation of why it fixes the problem would be appreciated.
I believe the following code will solve your problem. Add it to the AuditLogServiceImplementation and remove the #Resource annotation from the auditLogDao.
#Autowired
private ListableBeanFactory beanFactory;
#EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
auditLogDao = beanFactory.getBean(AuditLogDao.class);
}
You can do a similar trick in the filter too, whatever more comfortable for you.
I don't know what is the exact problem, but it's some kind of circular-dependency-like issue.
So by manually importing any bean which is affected in this loop, you can resolve the loop. You will set this one particular dependency AFTER Spring had created all of the other beans.

Unable to Understand how auto wiring is done in the below class

below is the class which has constructor args which gets autoWired, but what i don't understand is that how the constructor gets autowired here without specifying any annotation or without mentioning it in any xml file.
I am kind of baffled with the code.
#Loggable
#Slf4j
public class DefaultDirectPlusService extends AbstractDnBDirectPlusService implements DirectPlusService {
public DefaultDnBDirectPlusService(String baseURL, RestTemplate restTemplate, DnBMetricsRepository dnbMetricsRepository, Environment env) {
super(restTemplate, dnbMetricsRepository, env);
this.baseURL = baseURL;
}
Here the question is how does baseURL gets populated without any annotations or the xml configuration?
As specified in the documentation (https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/core.html#beans-autowired-annotation), starting with Spring 4.3, if a class has only one constructor, Spring will automatically use that constructor for autowiring.
If you would have more than one constructor (you can try it out), you need to add the #Autowired annotation to the constructor which you want Spring to use.

Get value from application.properties without Main application

I' m working in a Spring Boot project, consisted in several applications booted with embedded Tomcat and a unique application used only as library for running applications. In that library application I need to retrieve a value from application.properties file for a variable. Being it a library application, it has not a Main class, so the variable will be always null.
My try was these:
public class AuthAdapter implements IAuthAdapter {
#Value("${signin.key}")
private String key;
#Override
public String getSigningKey() {
return key;
}
}
When the getSigninKey() is invoked by an application that uses it, the variable key is null.
How can I do to fill the variable key with the value present on appliaction.properties file, considering the situation explained before?
You need to annotate your AuthAdapter class with #Service/#Component/#Repository/#Configuration based on your requirement. By doing so, spring boot will inject the application.properties to your class during the spring context initialization.
#Value Spring annotation
This annotation can be used for injecting values into fields in Spring-managed beans
So make AuthAdapter as spring bean in some config class
#Configuration
public class ApplicationConfig {
#Bean
public AuthAdapter getAuthAdapter() {
return new AuthAdapter():
}
}
with property in application.yml or application.properties
application.yml
signin:
key: value
Or if AuthAdapter is annotated with any stereotype annotations here, Just enable that class in ComponentScan
#SpringBootApplication
#ComponentScan({ "com.project1", "com.library.AuthAdapter" })
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}
If the variable key==null, this means that Spring did not inject it.
This could come from sevreral reasons:
the property "signin.key" is not present in the application.properties
SpringBoot did not start => make sure that in your application there is a main annoted with #springbootapplication
The AuthAdapter is not instanciate by Spring:
=> The AuthAdapter shall not be instanciate like:
authAdapter = new AuthAdapter();
Instead, it must be instanciate and injected by Spring itself like:
#Autowired
private authAdapter AuthAdapter;
For that the AuthAdapter must be annoted with a springBoot annotation:
#Service/#Component/#Repository/#Configuration.
Finally, the package containing the AuthAdapter class must be in the component scan perimeter to tell Spring to instanciate it.
Make sure that the "signin.key" is present in the application.properties and that the is present in the jar generated

Spring boot dependency bean not setting value [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 4 years ago.
In my Spring boot application, I have a dependency Spring project. From my SpringBoot class, I am trying to call a dependency class but the class has no value set.
#CrossOrigin(origins = "*")
#RestController
#Configuration
#ComponentScan(basePackages = "com.dependency.package")
public class BootClass {
private DependencyClass dependencyClass;
public BootClass() {
this.dependencyClass = new DependencyClass();
}
}
My DependencyClass object just gives me an empty object {}. Any ideas?
My Dependency class looks like this:
#Component
public class DependencyClass {
#Value("${jdbc.driver.class.name}")
private String driver;
#Value("${jdbc.url}")
private String url;
}
Thank you,
Julian
This is the classic Spring beginner mistake: calling new to instantiate an object.
You cannot call new if you want Spring to manage beans and provide dependencies. You have to give it to the Spring bean factory to manage. It's all or none.
Yours looks like a perfect case for constructor injection.
#Configuration
#ComponentScan(basePackages = "com.dependency.package")
public class BootClass {
private final DependencyClass dependencyClass;
#Autowired
public BootClass(#Qualifier(name = "dependencyClass") DependencyClass dependencyClass) {
this.dependencyClass = dependencyClass;
}
}
Surely you can think of a better name for DependencyClass. I'd suggest something like DatabaseConfiguration.
That is not to say that every object should be under the control of the bean factory, or that new should never be called. Objects with short scope that aren't shared can certainly be instantiated.
It's objects that require dependency injection that need to be under the control of the bean factory.
Just Mark that with #Autowired Annotation as shown below. That would do.
#Autowired
private DependencyClass dependencyClass;
Extending the answer of #duffymo:
Once you are done what he suggested, also make sure that "jdbc.driver.class.name" and "jdbc.url" are present in your main project properties file. If you are expecting that these values will be populated just because you have it in
properties file of "Dependent" project, you might get disappointed. Check this for more details:
https://stackoverflow.com/a/49564724/3458292

#Inject not injecting and causing NullPointerException using component scanning

My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.

Categories

Resources