Getting null value from #configuration - spring-boot

I'm creating pojo class and store the application.properties variable but I'm getting null values
NOTE: need to access env from my Abstract class
POJO class
package mynt.xyz.c4.pushnotif.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
#Configuration("notificationEnvironment")
#ConfigurationProperties(prefix = "app.notif")
public class NotificationEnvironment {
private String key;
private String url;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Initializing class with #autowired
public abstract class NotificationBase {
#Autowired
NotificationEnvironment notificationEnvironment;
public void getEnv(){
system.out.println(notificationEnvironment.getKey()); // null value
}
}
concrete class that extend to my NotificationBaseClass
#Component
#Qualifier("androidNotification")
public class AndroidNotification extends NotificationBase implements Notification {
public AndroidNotification(String message, String title, String datalink, List<String> instanceIds) {
super(message, title, datalink, instanceIds);
}
AndroidNotification(){
super();
}
#Override
public void send() {
this.getEnv();
}
}
application.properties
app.notif.key=jkashdkjashd
app.notif.url=https/some.url

You can auto wire #Configuration class from #Configuration class
#Configuration class may reference the instance of any other #Configuration class using #Autowired. This works because the #Configuration classes themselves are instantiated and managed as individual Spring beans.

Make your class #Component and add prefix value in #ConfigurationProperties, like this. This works for me, hope this works for you as well.
#Component
#ConfigurationProperties(prefix = "app.notif")
public class NotificationEnvironment {
private String key;
private String url;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
You can use this properties like this:
#Component
public class NotificationBase {
private static NotificationEnvironment notificationEnvironment;
#Autowired
public NotificationBase(NotificationEnvironment notificationEnvironment){
this.notificationEnvironment = notificationEnvironment;
}
public static void getEnv(){
System.out.println(notificationEnvironment.getKey()); // null value
}
}

Here is the one of the concrete class definition as OP author mentioned.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ConcreteNotification extends NotificationBase {
#Autowired
public ConcreteNotification(NotificationEnvironment notificationEnvironment) {
super(notificationEnvironment);
}
}
updated NotificationBase as below
public abstract class NotificationBase {
NotificationEnvironment notificationEnvironment;
public NotificationBase(NotificationEnvironment notificationEnvironment) {
this.notificationEnvironment = notificationEnvironment;
}
public void getEnv(){
System.out.println(notificationEnvironment.getKey());
}
}
The controller class I am using to get configuration values
#RestController
public class ArticleCommentController {
#Autowired
ConcreteNotification concreteNotification;
#RequestMapping(value = "/health_check", method = RequestMethod.GET)
public void getDemo() {
concreteNotification.getEnv();
}
}
output:
jkashdkjashd

Related

Spring Boot #ConfigurationProperties

so I'm kinda new to Springboot and I'm trying to get the value from application.properties. I want to get multiple value from the application.properties and insert it into a list. At first, I tried to get the value from controller class and it works. Now I tried to get the value from a new class, but the value won't show up and it's showing an error because it says that it's null. Am i missing an annotation or did i do something wrong in the code? Below is my code.
application.properties:
example.name[0] = asdf
example.name[1] = qwer
List Value class:
#ConfigurationProperties(prefix = "example")
#Configuration
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
What i tried in controller and worked:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
#Autowired
NameProperties property = new NameProperties();
#GetMapping
public String tes() {
String name = property.getName().get(0);
System.out.println(name);
return name;
}
}
In the new class that doesn't work:
#Component
public class NameConfiguration {
#Autowired
NameProperties property = new NameProperties();
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}
The code to test the new class in the controller:
#RestController
#CrossOrigin
#RequestMapping("/tes/**")
public class NameController {
NameConfiguration conf = new NameConfiguration();
#GetMapping
public String tes() {
conf.getName(0);
}
}
Is it because the value doesn't get injected when I call the class or what should I do? Appreciate any kind of help. Thanks!
Hello friend when you declare your class as a Spring Bean you shouldn't initialize the object yourself other the properties define in it will not be injected by Spring, so you should let spring help you with that, try these class below
NameProperties
#Component
#ConfigurationProperties(prefix = "example")
public class NameProperties {
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
NameConfiguration.java
#Component
public class NameConfiguration {
#Autowired
NameProperties property;
public void getName(int index) {
System.out.println(property.getName().get(0));
}
}

Wrong profile is active

#SpringBootApplication
public class SfgDiApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(SfgDiApplication.class, args);
PetController petController = ctx.getBean("petController", PetController.class);
System.out.println("--- The Best Pet is ---");
System.out.println(petController.whichPetIsTheBest());
}
#Controller
#ResponseBody
public class PetController {
public PetController(PetService petService) {
this.petService = petService;
}
private final PetService petService;
#GetMapping("pet-type")
public String whichPetIsTheBest(){
return petService.getPetType();
}
}
public interface PetService {
String getPetType();
}
#Service("cat")
public class CatPetService implements PetService {
#Override
public String getPetType() {
return "Cats Are the Best!";
}
}
#Profile({"dog", "default"})
public class DogPetService implements PetService {
public String getPetType(){
return "Dogs are the best!";
}
}
application.properties
spring.profiles.active=dog
Result
--- The Best Pet is ---
Cats Are the Best!
I don't understand why cats are here. I can even comment the properties out, but cats are still here. I would like to see dogs.
What can I try next?
It looks like the DogService is not a bean. So in the end you only have a single bean (CatService) and this one will be picked all the time.
You should define a bean of DogPetService with #service.
You should add the cat profile to CatPetService.
Like this :
#Service("cat")
#Profile({"cat"})
public class CatPetService implements PetService {
#Override
public String getPetType() {
return "Cats Are the Best!";
}
}
#Profile({"dog", "default"})
#Service("dog")
public class DogPetService implements PetService {
public String getPetType(){
return "Dogs are the best!";
}
}
I think you can achieve what you want like this:
#Configuration("petConfig")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class PetConfig {
#Value("${spring.profiles.active}")
private String type;
#Bean(name = "petService")
#Primary
public PetService petService() {
PetService petService = null;
if ("cat".equals(type)) {
petService = new CatPetService();
}
if ("dog".equals(type)) {
petService = new DogPetService();
}
return petService;
}
}
Annotate both CatPetService and DogPetService with #Service. This way you can easily adapt the code without hardcodings and duplication.

Annotation #Value is not working in my service

I have my main configuration
#EnableScheduling
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "gr.citystore.web.helios.yeastar" })
#PropertySource(value = { "classpath:application.properties" })
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {
#Autowired
private MyServiceImpl myService;
#EventListener(ContextRefreshedEvent.class)
public void contextRefreshedEvent() {
MyThread mThread = new MyThread(myService);
}
}
And my service the code is:
#Service("myService")
#PropertySource(value = { "classpath:application.properties" })
public class MyServiceImpl implements MyService{
#Value("${property.api.ip}")
private String apiIP;
#Value("${property.api.port}")
private String apiPort;
public String myMethod() {
}
}
My problem is that the #Value annotation is not working when I pass it as argument in myThread, instead is return "${property.api.port}".
What I am missing here?
EDIT:
The application.properties file location is "src/main/resources" and the content is:
property.api.ip = 12.34.50.30
property.api.port = 50034
You could just inject the values of the application.properties into your class like this:
#Service("myService")
public class MyServiceImpl implements MyService{
private final String apiIP;
private final String apiPort;
public MyServiceImpl(#Value("${property.api.ip}") String apiIP,
#Value("${property.api.port}") apiPort) {
this.apiIP = apiIP;
this.apiPort = apiPort;
}
public String myMethod() {
}
}

JUNIT - Null pointer Exception while calling findAll in spring Data JPA

I am new to Junits and Mockito, I am writing a Unit test class to test my service class CourseService.java which is calling findAll() method of CourseRepository.class which implements CrudRepository<Topics,Long>
Service Class
#Service
public class CourseService {
#Autowired
CourseRepository courseRepository;
public void setCourseRepository(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
public Boolean getAllTopics() {
ArrayList<Topics> topicList=(ArrayList<Topics>) courseRepository.findAll();
if(topicList.isEmpty())
{
return false;
}
return true;
}
}
Repository class
public interface CourseRepository extends CrudRepository<Topics,Long>{
}
Domain class
#Entity
#Table(name="Book")
public class Topics {
#Id
#Column(name="Topicid")
private long topicId;
#Column(name="Topictitle",nullable=false)
private String topicTitle;
#Column(name="Topicauthor",nullable=false)
private String topicAuthor;
public long getTopicId() {
return topicId;
}
public void setTopicId(long topicId) {
this.topicId = topicId;
}
public String getTopicTitle() {
return topicTitle;
}
public void setTopicTitle(String topicTitle) {
this.topicTitle = topicTitle;
}
public String getTopicAuthor() {
return topicAuthor;
}
public void setTopicAuthor(String topicAuthor) {
this.topicAuthor = topicAuthor;
}
public Topics(long topicId, String topicTitle, String topicAuthor) {
super();
this.topicId = topicId;
this.topicTitle = topicTitle;
this.topicAuthor = topicAuthor;
}
}
Following is the Junit class I have written but courseRepository is getting initialized to NULL and hence I am getting NullPointerException.
public class CourseServiceTest {
#Mock
private CourseRepository courseRepository;
#InjectMocks
private CourseService courseService;
Topics topics;
#Mock
private Iterable<Topics> topicsList;
#Before
public void setUp() {
MockitoAnnotations.initMocks(CourseServiceTest.class);
}
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
boolean result=courseService.getAllTopics();
assertTrue(result);
}
}
Change the setUp() method to:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Probably you are dealing with some problem on the framework to make the mocked class be injected by the framework.
I recommend to use Constructor Injection, so you don't need to rely on the reflection and #Inject/#Mock annotations to make this work:
#Service
public class CourseService {
private final CourseRepository courseRepository;
// #Autowired annotation is optional when using constructor injection
CourseService (CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
// .... code
}
The test:
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
CourseService courseService = new CourseService(courseRepository);
boolean result = courseService.getAllTopics();
assertTrue(result);
}

#Configurable not working on Subclass

Take the following general abstract class:
#Configurable
public abstract class TestEntityRoot {
public abstract String print();
}
And a subclass:
#Configurable
public class TestEntity extends TestEntityRoot{
private TestEntityService testEntityService;
#Autowired
public void setTestEntityService(TestEntityService testEntityService) {
this.testEntityService = testEntityService;
}
#Override
public String print() {
return testEntityService.print();
}
}
When call controller:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntity entity = new TestEntity();
return entity.print();
}
}
everything ok. But if call like this:
#RestController
public class TestEntityController {
#GetMapping(name = "/test")
public String print() {
TestEntityRoot entity = new TestEntity();
return entity.print();
}
}
i get null pointer. Is it possible that second example work?
In the second case you create manually the class rather than using spring's bean. Autowire the bean instead. See
#RestController
public class TestEntityController {
#Autowired
private TestEntity entity
#GetMapping(name = "/test")
public String print() {
return entity.print();
}
}

Resources