#Value not Injecting ANY value - java

I'm learning how to create a RESTful API with Springboot, and the #Value tag is not injecting values from application.properties, nor is it injecting values specified in the tag itself. I have my project structured as such:
api
config
controllers
model
services
SpringApplication.java
resources
application.properties
Strangely, this behavior only seems to occur within files located in my "services" folder. The #Value tag works as expected in files located in my "controllers" folder. Below are examples of what I am doing:
#Value("${var}")
String variable
"var" is defined in application.properties as var=some_stringbut variable is still initialized as 'null'
#Value("I am directly assigning a value to this variable, but it still comes out null")
String variable
I believe I am using the correct import: import org.springframework.beans.factory.annotation.Value.
At first I just thought the "services" folder was blind to the directory where application.properties is located, but after trying to directly inject values, I'm not so sure what to think.
Edit
All of the classes in the services folder are annotated with #Service and nothing else. Below is what the class looks like. I've opted to leave out implementations of the methods, other variables, and irrelevant imports. The code/methods all work as expected when hard-coding the variables. My focus is the #Value tag.
package myapi.api.services;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class MyService {
#Value("${var}")
String variable;
public List<Data> getData() {
return new ArrayList<Data>();
}
public void postData() {
}
Edit 2
Below is the APIController class, stored in the "controllers" folder. Again, I've opted to leave out irrelevant methods/imports/variables. I would also like to note, that the #Value tag works as expected in this class.
package myapi.api.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import myapi.api.services.MyService;
import lombok.RequiredArgsConstructor;
#RestController
#RequestMapping("api")
#RequiredArgsConstructor
public class APIController {
#Autowired
private final static MyService myService = new MyService();
#GetMapping("/getdata")
public List<Data> getData() {
return myService.getData();
}
}

#Autowired
private final static MyService myService = new MyService();
Three issues:
First, you cannot have a new operator. Spring controls the lifecycle of your class instances. It will call new for you in the background. Remove the entire new operator stanza.
Next: your your field cannot be final. After construction of the class, Spring will need to modify that field with a proxy. Remove the final declaration;
Finally: your field cannot be static. static variables have a certain lifecycle with the JVM, and you need to let the Spring framework manage your lifecycle. remove the static operator.
The correct declaration should be:
#Autowired
private MyService myService;

Related

#Value application.properties come with a null URL

I'm having a pretty annoying problem with application.properties.
I have a Java 11 project with Spring boot working perfectly, I can get all values ​​normally using :
#Value("${example}")
Except when I try to get this URL coming from properties. This url is passed and called in a RestTemplate, and it always comes null.
#Value("${url}")
private String url
#Autowired
private RestTemplate restTemplate;
restTemplate.postForObject(url,new HttpEntity<>(getBody(),getHeaders()), DTO.class);
By hovering the mouse over the (${"url"}, the http appears: saying it is capturing, but when it reaches the part of the code that goes through #RestTemplate, the value is null.
I put up a log.info(url) and on Springboot's climb it shows the correct value with the url, but when it goes through the code line: the value comes to null
If I go directly to the class:
private static String URL = "http:example.com" , the code runs fine.
My application.properties in folder of project/src/main/resources
server.port=8088
url=http://example.com
spring.rabbitmq.port=5672
spring.rabbitmq.username=user
spring.rabbitmq.password=password
spring.rabbitmq.host=rabbitm.example.com
spring.rabbitmq.template.exchange=test-sender
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.multiplier=2
My code:
package com.test;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
#Data
#AllArgsConstructor
#NoArgsConstructor
#Service
public class TestService {
#Value("${url}")
private String url; //coming from properties is always null
//private static String URL1 = "http.com.example"; //
// this way works as static
#Autowired
private RestTemplate restTemplate;
#PostConstruct
public void print() {
System.out.println(url);
}
public TestResponseServiceDTO getTest(){
log.info(url) // here also shows a correct url on the console
System.out.println(url) // here also shows a correct url on the console
// Even at this point in my code, the url comes from the line below and it comes null
TestResponseServiceDTO response=restTemplate.postForObject(url, // Here the URL appears null
new HttpEntity<>(getbody(),getHeaders()),TestResponseServiceDTO.class);
return response;
}
}
How can I get around this?
You've declared the property in question as following, which is incorrect
#Value(${"url"})
private String url;
Try changing it to
#Value("${url}")
private String url;
Now if you've mentioned the url in the properties file and the above class is a bean managed by spring (annoated by component or service) then url won't be null unless you set it to null again later in the code prior using it in the rest template call.
Another case: Also, make sure that you should invoke the getTest() method from spring managed bean. So, you shouldn't be doing something like this.
TestService testService = new TestService();
testService.getTest();
Couldn't find any issue in the code you have provided.
First thing we have to understand is if the value was not resolved when application startup, application won't even start. Plus even you have mentioned that when you hover over ("${url}") value is captured!
I can see you have print the value of url to console in your PostConstruct method. First thing what you can do check that.
Only reason I can think of is, value of url is changed at run time by mistake or on purpose. You can avoid this from happening by removing #Data annotation from your TestService class. I don't see an reason why would you need #Data, #AllArgsConstructor, #NoArgsConstructor annotations in the first place. Specially #Data, because it can introduce unnecessary mutability to your TestService class. You can use #Getter if you need to access private variables.

Spring `JpaRepository` to be used only in test scope

I have a JpaRepository, that looks like
#Repository
public interface CustomRepository extends JpaRepository<EntityType, Integer> {
// Methods
}
which could possibly have queries that would run for long, in which case I need to enforce a timeout. I have successfully added the timeout-related configuration (the connection pool being used is Druid, if that matters) and now I want to test it in a unit test. I am using the following method in my JpaRepository<T, ID> interface.
#Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(#Param("count") Long count);
This method runs successfully and demonstrates the expected behavior. However, given that this method will run longer as the value given to parameter count becomes larger, having this in the production code, just for the sake of testing the timeouts, bothers me to my core, as this might end up being a vulnerability that could be leveraged to launch a denial attack.
So to the question, is some way I can use this exact method in my test scope, without having that going in the production code?
Turns out, it's not that complicated. Given that this project is running on Spring, I can have an extension of the above repository in my test sources, as follows.
package com.project.package.repo;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
#Repository
public interface TimedCustomRepository extends CustomRepository {
#Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(#Param("count") Long count);
}
As I have JUnit4, I can have a test class which will run on Spring boot, like follows.
package om.project.package.repo;
import com.github.database.rider.spring.api.DBRider;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.context.junit4.SpringRunner;
#SpringBootTest
#RunWith(SpringRunner.class)
#DBRider(dataSourceBeanName = "primaryDataSource") //Data source wiring; Not that important.
public class TransactionHistoryJpaRepoTest {
#Autowired //---(1)
private TimedCustomRepository timedCustomRepository;
#Test(expected = JpaSystemException.class)
public void whenQueryTimeoutOccurs() {
timedCustomRepository.run(100000000L);
}
}
The property at (1) will be wired using the repository bean which we have created above, and this test will execute as expected. Given the bean TimedCustomRepository extends CustomRepository, the data source configuration and everything will be the same. Most importantly, since this method with a long running query is now only on the test scope, it will not have any impact beyond the test scope.

SpringBoot #Autowire why does this example work?

I have created this class:
import org.springframework.stereotype.Component;
...
#Component("notTheNameTestMe") //shouldnt this only work with testMe ?
public class TestMe {
public void showMsg() {
System.out.println("Autowiring works");
}
}
And I'm using it this way in a second class (or better: controller):
import com.example.TestMe; //shouldnt this be not necessary with autowire? But getting error else...
...
#Autowired
private TestMe testMe;
...
this.testMe.showMsg();
But this works perfectly (so maybe Im not really using autowire here?), it even works if I rename the whole TestMe class to TestMeSomething (if I adjust the import in the second class)
I dont really understand what #Autowired does. I thought it just scans for SpringBoot Components (which are named by the string in #Component() and when it finds a match it Injects the dependancy. But in my example the match is impossible and I still can see the message "Autowiring works" in the console. This shouldnt be like this if I would really use autowire here or? What am I understanding in a wrong way? What is the difference to using new TestMe() then? I have the dependancy already with the import or? So not a real dependancy injection, or?
Spring is not operating on the name in the #Component annotation. Rather it's using the name of the class. It's simply finding a class named TestMe because that's the type of the variable you've annotated with #Autowired.

Purpose of Service Interface Class in Spring Boot

My question is regarding the use of the interface class. I am fairly new to Spring so please bear with me if this is overly simple.
First of all, what is the point of having an IBoxService interface here when you could just declare the find all in BoxService. Secondly, in the controller how is IBoxService being used. Meaning, we are calling IBoxService.findAll(). But, how is this being tied to the BoxService class. What if multiple service classes implemented IBoxService? Is this a java thing or a Spring injection thing. Thanks.
package com.xyz.service;
import com.xyz.model.Box;
import java.util.Set;
public interface IBoxService {
Set<Box> findAll();
}
package com.xyz.service;
import com.xyz.model.Box;
import com.xyz.repository.BoxRepository;
import java.util.Set;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
#Service
#AllArgsConstructor
#Slf4j
#Transactional
public class BoxService implements IBoxService {
#Autowired
private BoxRepository boxRepo;
#Override
public Set<City> findAll() {
return (Set<City>) repository.findAll();
}
}
package com.xyz.controller;
import com.xyz.model.Box;
import com.xyz.service.IBoxService;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/api/box")
public class BoxController {
#Autowired
private IBoxService boxService;
#GetMapping
public ResponseEntity<Set<Boxes>> allBoxes() {
return (Set<Box>) boxService.findAll();
}
}
There are various reasons why Service layer interfaces are created. The first and most important reason is testability. You can create mocks of service interface and test your code easily, if you cannot create mocks using a mocking library then you can create test stubs.
One more reason is, we can achieve loose coupling between Controller and Service layer. Suppose you want to entirely change the implementation of service, you can create new service implementation and inject that implementation by injecting new bean by qualifier name
Please understand basic Java and use of interface . Spring boot is just abstraction over Java hence all the basic concepts applies as it is.
Coming back to your questions IBoxService is a interface which allows to inject required implementation of it at controller level. As of now only implementation of IBoxServic is BoxService hence it is getting injected automatically. In case you have multiple implementations you need to use qualifier annotation to specify kind of implementation you need to inject. Or you can create object bu yourself using class names
Consider below:
IBoxService is implemented by two classes BoxService and TiffinBoxService
Now in controller you can inject implementation which you want. Which allow us to achieve principle of interface which is hide internal details.
User which is controller in this case doesn't need to know which class is being use internally as we are using reference of interface.
List interface is best example which has ArrayList and LinkedList as implementation classes.
Hope it is useful !!

How can i get spring-boot main-class package name

I want to make a spring-boot starter,so i need to get package name of application main-class.
How can i get it?
Sometimes,you can use listener for spring boot,but it must configure in application.properties.
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.ApplicationContext;
AutoConfigurationPackages.get(context.getAutowireCapableBeanFactory())
By this method, you can get the package of you current class.
MethodHandles.lookup().lookupClass().getPackage().getName()
You could use the fact that the main class will problably be annotated with #SpringBootApplication and search for that class in the Spring Context. Implementing something like:
#Service
public class ApplicationFinder {
#Autowired private ApplicationContext context;
public String findBootClass() {
Map<String, Object> candidates = context.getBeansWithAnnotation(SpringBootApplication.class);
return candidates.isEmpty() ? null : candidates.values().toArray()[0].getClass();
}
}
Once you jave the class name you can string slice it to extract the package.

Categories

Resources