I am new to quarkus environment. I have a quarkus application where I'm trying to inject the property config using
org.eclipse.microprofile.config.inject.ConfigProperty
Here is the sample code
public class Temp {
#ConfigProperty(name = "secret.token")
static String SECRET_KEY;
public void display() {
System.out.println(SECRET_KEY);
}
}
Here is the content of my application.properties
secret.token = ${TOKEN_SECRET:Root}
Here display method is always printing null.
The thing is the same property is being injected into the controller/resource endpoint classes properly but not in this class. I also tried using #Inject along with #ConfigProperty but no luck. Any pointers would really help.
The class on which the annotation is used, needs to be a CDI bean.
The easiest way to accomplish that is to annotate the class with #Singleton and use with something like #Inject Temp temp wherever the class is used.
See https://quarkus.io/guides/cdi for an intro to CDI
Related
I need to assure data migration using mongock.
The #ChangeUnit class holds the logic for migration. It has a field annotated with #Value which is always null, even though I properly initialized in application.properties:
mongock.migration-scan-package=my.package
login-secret=test
Then the MigrationConfiguration looks as follows:
#ChangeUnit(id = "test", order = "001", author = "test")
#RequiredArgsConstructor
#Configuration
public class InitUsersChangeLog {
private final MyService service;
private final MongoTemplate template;
#Value("${login-secret}")
private String LOGIN;
#Execution
public void initUser() {
service.create(User.builder().login(LOGIN).build());
}
}
Main class:
#EnableMongock
#SpringBootApplication
public class MailServiceApplication {...}
My assumption is that this value is not injected properly into the MongockConfiguration bean. I tried to configure the bean manually (without using mongock.migration-scan-package=my.package) in the properties, but with no success.
As Mongock currently doesn't support #Value annotation you can try to use getProperty method from Environment bean. Environment bean can be injected same as other beans using constructor or Lombok annotations.
You want to change this:
#Value("your.key.property")
to that:
private final Environment env;
public void method(){
env.getProperty("your.key.property")
}
Mongock currently no supports #value injection via field o method parameter. We will provide that in a future minor release within version 5, but we can't give you dates, yet.
Extending MichalJ's answer, which is absolutely valid. I would like to add that the changeUnits are not retrieved by Mongock via Springboot, they are processed by Mongock independently. So the annotation #Configuration, #Component, etc. won't be taken into account and they could even be damaging.
Related to that, this code won't work, at least not in a near future:
#Value("${login-secret}")
private String LOGIN;
First, as said, Mongock doesn't support value currently, but the first approach will require the constructor parameter to have that #Value("${login-secret}"), not at the field level.
I'm relatively new to using Dagger and I have been reading up on the documentation here - https://google.github.io/dagger/users-guide. I was previously using Spring for DI. One thing which I was still not sure was - How to read environment variables in Dagger.
For example, in Spring, I'd just do:
#Value("${envVariable}")
private String myEnvVariable;
#Bean
public MyClass myclass() {
return new MyClass().builder().property(myEnvVariable).build();
}
I'm not sure if I'm somehow conflating the usage of Dagger as for reading environment variables.
I was assuming that in Dagger I'd have a Module which constructs the MyClass and then I'd use the #Inject annotation to inject the dependency, but wasn't sure how I'd get the value of the environment variable.
I ended up defining a method which would do something like this:
#Provides
#Named("ENV_VARIABLE_NAME")
#Singleton
public String getMyEnv() {
return System.getenv("ENV_VARIABLE_NAME");
}
For usage, I have the #Named annotation, and therefore I'd just inject a String with the Named annotation in my other Module classes.
I'm new to Spring and I'm building an application where some entities (JPA/Hibernate) need access to a property from application.properties. I do have a configuration class in which this is trivial:
#Configuration
public class FactoryBeanAppConfig {
#Value("${aws.accessKeyId}")
private String awsAccessKeyId;
#Value("${aws.secretKey}")
private String awsSecretKey;
}
but since entities do not have and I think they should not have the annotations such as #Configuration or #Component, what's the Spring way for them to access the property?
Now, I know I can create my own class, my own bean, and make it as a simple wrapper around the properties; but is that the Spring way to do it or is there another way?
specify Property file location using #PropertySource
Something like below
#PropertySource("classpath:/application.proerties")
You also need to add below bean in your config
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
There is no "Spring way", since JPA entities and Spring have nothing to do with each other. Most importantly, JPA entities are not Spring beans, so Spring doesn't know or care about them as they're not managed by Spring.
You can try to hack around, trying in vain to access Spring's configuration from code that should not be trying to access it, or you can accept the truth that your design is broken and you're trying to do something that's not meant to be done.
As was proposed several times, use a service class for this. It's managed by Spring, so it can access the Spring config, and it can handle entities, so there's no crossing boundaries.
First create a public static variable in some bean managed by Spring, then make the following use of the #Value annotation.
public static String variable;
#Value("${variable}")
private void setVariable(String value) {
variable = value;
}
It will be set at runtime on startup, now you can access it from entities and everywhere else because it is just a public static var.
You can use #PropertySource to load the properties file as follows
#Configuration
#PropertySource("classpath:/com/organization/config/application.proerties")
public class FactoryBeanAppConfig {
...
}
Entities should not acces environment properties. If you are using your entity through a service, then the service can access the properties to act on the entity.
I have a class as such.
public class Foo {
#Autowired
private Bar bar;
}
The class Bar lives in a jar that comes from a dependency pulled in from Maven. How can I add that class to the Spring context so that it will be properly autowired? I can't add the #Component to the source code. Is there a way to do it without XML? I'm currently trying to stick with annotation driven injection as much as possible.
I'm using Spring 3.1.4-RELEASE
It appears from your description that you know exactly which class is being instantiated. If that's the case, then in one of your #Configuration classes, you can simply create the appropriate bean, and Spring will configure it before deployment into the context:
#Bean public Foo foo() {
return new Foo();
}
Is it possible to use #Configurable on a class that's weaved using AspectJ and get Spring to load in values on fields/methods which are annotated with #Value?
I know its possible with #Autowired and #Resource etc... Are there any others.
e.g.
#Configurable
public Class MyObj{
#Value("$(my.prop)")
private String aField;
public String getAField(){
return aField;
}
}
And then have something like
public aMethodSomewhereElse(){
MyObj obj = new MyObj()
assertNotNull(obj.getAField());
}
Are there any alternatives to being able to create MyObj with the new operator and still get spring to handle the annotations?
--EDIT:--
It IS possible to do this using new when using #Autowired, have a look at some Hibernate and JPA stuff with Spring and AOP... I've used this in the past to do some profiling of Java code. But I really want to use SPEL and #Value before I mock up a full example I was hoping to find the answer here. FYI - if you don't belive me the Spring Manual even says it is possible to do this, what I want to know is if its possible to use #Value annotations in the same scope...
The Spring container instantiates and configures beans defined in your
application context. It is also possible to ask a bean factory to
configure a pre-existing object given the name of a bean definition
containing the configuration to be applied. The spring-aspects.jar
contains an annotation-driven aspect that exploits this capability to
allow dependency injection of any object.
And...
Using the annotation on its own does nothing of course. It is the
AnnotationBeanConfigurerAspect in spring-aspects.jar that acts on the
presence of the annotation. In essence the aspect says "after
returning from the initialization of a new object of a type annotated
with #Configurable, configure the newly created object using Spring in
accordance with the properties of the annotation". In this context,
initialization refers to newly instantiated objects (e.g., objects
instantiated with the 'new' operator) as well as to Serializable
objects that are undergoing deserialization (e.g., via readResolve()).
http://static.springsource.org/spring/docs/3.0.0.RC2/reference/html/ch07s08.html
Cheers.
You are absolutely right - #Autowired fields will be wired in an #Configurable annotated class even outside of a Spring container, assuming that you have a AspectJ infrastructure in place.
You have noted a good catch though, #Value fields are processed by a Spring bean post processor(AutowiredAnnotationBeanPostProcessor), which resolves the #Value annotated fields. It does not act on objects instantiated outside of the container though - so in short, the #Autowired fields should get wired in, but #Value properties will not.
Doing
MyObj obj = new MyObj()
means that obj is not managed by spring, so it will not do autowiring.
Only way to do that is to obtain instance from an application context. For example:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyObj obj = context.getBean("myBean");
I don't think it is possible to use new operator and ask spring to autowire properties. I think 1 way to solve this is to get a static reference to applicationContext and create a prototype scoped bean.
#Component
public class ApplicationContextLocator {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public ApplicationContextLocator() {
super();
}
#Autowired
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextLocator.applicationContext = applicationContext;
}
}
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class MyObj {
.....
}
public aMethodSomewhereElse(){
MyObj obj = ApplicationContextLocator.getApplicationContext().getBean(MyObj.class)
assertNotNull(obj.getAField());
}