Am new to spring and spring boot. I was actually trying to a restclient in springboot. When i write the client and get the response, i wanted to read the response body which is String and wanted to convert that to JSON for my use. So i have written RestClient class and from that I have autowired JsonUtil class which does String to JSON. But my autowired jsonutil is not available for me to use in Rest client class. i dont know what i need to do here. Below is my code.
My RestClient
#Component
public class RestClient {
#Autowired
JsonUtil jsonUtil;
private static final String URL ="https://test.com?q=";
private static String getURL(String value){
if(!StringUtils.isBlank(value))
return URL+value;
return null;
}
private static void get(String val){
RestTemplate restTemplate = new RestTemplate();
String resourceUrl=getURL(val);
ResponseEntity<String> response = null;
if(!StringUtils.isBlank(resourceUrl)){
response = restTemplate.getForEntity(resourceUrl , String.class);
}
//Though i have autowired JsonUtil, i dont have that object to use it here
jsonUtil. //this variable is not available
}
My JsonUtil
import com.fasterxml.jackson.databind.ObjectMapper;
#Component
public class JsonUtil {
#Autowired
private ObjectMapper objectMapper;
public JsonUtil(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public JsonNode getStringAsJson(String value) {
try {
return objectMapper.readTree(value);
}catch (IOException e) {
String msg = e.getMessage();
LOG.info(msg);
}
return null;
}
}
Any help appreciated
You are trying to use an instance variable inside a static function. That is not possible. Think of it this way, there can be numerous instances of the class with each having its own particular instance variable. How will the static method know which one to pick.
You should make the methods non static to make it work.
However, if you are determined to make the function static make the variable also static and since you can't autowire static fields, try something like this
private static JsonUtil jsonUtil;
#Autowired
ApplicationContext ctx;
#PostConstruct
public void init() {
jsonUtil = ctx.getBean(JsonUtil.class);
}
Related
Is it possible to write unit test using Junit 5 mockito for retryable annotations?
I am having a service interface which has only one method, which downloads the file from remote url
#service
interface downloadpdf{
#Retryable(value = { FileNotFoundException.class, HttpClientErrorException.class }, maxAttempts = 5, backoff = #Backoff(delay = 1000))
public string downloadpdffile(string remoteurl, string pdfname);
}
I have tried referring sites and found using Spring4JunitRunner implementation to test retry. Got confused with implementation. Is it possible to write unit test using Junit 5 mockito for retryable annotations?. Could you please elaborate on the solution here?
You need to use #SpringJUnitConfig (which is the equivalent of the JUnit4 runner). Or #SpringBootTest as you are using Boot.
#Retryable only works with beans managed by Spring - it wraps the bean in a proxy.
#SpringBootApplication
#EnableRetry
public class So71849077Application {
public static void main(String[] args) {
SpringApplication.run(So71849077Application.class, args);
}
}
#Component
class RetryableClass {
private SomeService service;
void setService(SomeService service) {
this.service = service;
}
#Retryable
void retryableMethod(String in) {
service.callme();
throw new RuntimeException();
}
#Recover
void recover(Exception ex, String in) {
service.failed();
}
}
interface SomeService {
void callme();
void failed();
}
#SpringBootTest
class So71849077ApplicationTests {
#MockBean
SomeService service;
#Test
void testRetry(#Autowired RetryableClass retryable) {
SomeService service = mock(SomeService.class);
retryable.setService(service);
retryable.retryableMethod("foo");
verify(service, times(3)).callme();
verify(service).failed();
}
}
I was also trying to implement this using Junit5.
Tried various options but that didn't help. Then after googling for few hours, got the following link and it helped to succeed.
https://doctorjw.wordpress.com/2022/04/29/spring-testing-a-single-bean-in-junit-5-springextension/
Reference code below, for detailed explanation, please refer the blog.
#Component
public class MyClass {
private ObjectMapper objectMapper;
private RestTemplate restTemplate;
#Value("${testValue:5}")
private int value;
#Retryable(....)
public void doStuff() throws SomeException {
...
}
}
What I’ve discovered is, if I declare my test class this way:
#ExtendWith( SpringExtension.class )
#Import( { MyClass.class, ObjectMapper.class } )
#EnableRetry
public class MyClassTest {
#Autowired
private MyClass myClass;
#MockBean
private RestTemplate restTemplate;
#Autowired
private ObjectMapper objectMapper;
#BeforeEach
public void setup() {
// If we are going to jack with the object configuration,
// we need to do so on the actual object, not the Spring proxy.
// So, use AopTestUtils to get around the proxy to the actual obj.
TestingUtils.setFieldValue( AopTestUtils.getTargetObject( myClass ), "value", 10 );
}
}
You will notice the inclusion of 1 other class, TestingUtils.class. This class looks like:
public class TestingUtils {
public static void setFieldValue( Object object, String fieldName, Object value ) {
Field field = ReflectionUtils.findField( object.getClass(), fieldName );
ReflectionUtils.makeAccessible( field );
ReflectionUtils.setField( field, object, value );
}
}
All credits goes to the author of the blog.
I'm still learning programming languages java and spring, during learning, I saw a new way to create dependency injection before I use this type.
#RestController
#RequestMapping("/api/car")
public class CarController {
final CarServiceImp carServiceImp;
final RestTemplate restTemplate;
public CarController(CarServiceImp carServiceImp, RestTemplate restTemplate) {
this.carServiceImp = carServiceImp;
this.restTemplate = restTemplate;
}
#GetMapping("/getcars")
public Response getCarByPage(#RequestParam Integer page,#RequestParam Integer size,#RequestParam String price) {
return carServiceImp.getCarByPage(page,size,price);
}
#GetMapping("/car")
public Response getAllCarFromAutoShop(#RequestParam(name = "autshopId") Integer id) {
return carServiceImp.getAllCarFromAutoShop(id);
}
#PostMapping
public Response addAllCar(#RequestBody List<Car> carList) {
return carServiceImp.addAll(carList);
}
#PostMapping("/one")
public Response addOneCar(#RequestBody Car car) {
return carServiceImp.addOne(car);
}
}
here new way of using DI my question when using access modifier with DI and annotation #Autowired with constructor, and which one is comfortable for use by the way thank you for your answer
#RestController
#RequestMapping("/api/car")
public class CarController {
private final CarServiceImp carServiceImp;
private final RestTemplate restTemplate;
#Autowired
public CarController(CarServiceImp carServiceImp, RestTemplate restTemplate) {
this.carServiceImp = carServiceImp;
this.restTemplate = restTemplate;
}
#GetMapping("/getcars")
public Response getCarByPage(#RequestParam Integer page,#RequestParam Integer
size,#RequestParam String price) {
return carServiceImp.getCarByPage(page,size,price);
}
#GetMapping("/car")
public Response getAllCarFromAutoShop(#RequestParam(name = "autshopId") Integer id) {
return carServiceImp.getAllCarFromAutoShop(id);
}
#PostMapping
public Response addAllCar(#RequestBody List<Car> carList) {
return carServiceImp.addAll(carList);
}
#PostMapping("/one")
public Response addOneCar(#RequestBody Car car) {
return carServiceImp.addOne(car);
}
}
Before Spring 4.3 the #Autowired annotation was needed. Since then, it is optional if there is only one constructor.
There are three options for injection in spring: field injection, setter injection and the preferable constructor injection (the one you used).
The constructor injection is to be preferred, because you can be certain that all needed dependencies are injected, if the constructor expects all required dependencies as parameters. This way the class will not be instanciated without the required dependencies.
The visibility of fields in a class should always be private, if not needed otherwise.
I am trying to write a Java unit test using Mockito but am having trouble to get a matcher to work.
I want to test the following class
CustomService.java
public class CustomService {
private final ApplicationProperties props;
public CustomService(ApplicationProperties props){
this.props = props;
}
private final ObjectMapper mapper = new ObjectMapper();
public void method(JsonNode message) throws CustomException {
try {
List<String> actions = mapper.readValue(message.get("actions").toString(), mapper.getTypeFactory().constructCollectionType(List.class, String.class));
System.out.println(actions);
} catch (IOException ex){
throw new CustomException(ex);
}
}
}
I have a CustomException class
CustomExcepton.java
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class CustomException extends Exception {
public CustomException(Throwable cause) {
super(cause);
}
}
I want to test that the CustomException is thrown. I am using Mockito. I have tried the below but the given statement doesn't seem to pick up the (readValue) line of code in the method
CustomServiceTest.java
public class CustomServiceTest {
private final ApplicationProperties props = mock(ApplicationProperties.class);
private final CustomService customService = new CustomService(props);
private static final ObjectMapper objectMapper = new ObjectMapper();
#Test
public void CustomExceptionIsThrown() throws Exception {
ObjectMapper mapper = mock(ObjectMapper.class);
given(mapper.readValue(anyString(), any(TypeReference.class))).willThrow(new IOException("This is a test"));
String json = "{\"actions\":[\"ac1\",\"ac2\",\"ac3\",\"ac4\"]}";
JsonNode d = objectMapper.readTree(json);
assertThrows(CustomException.class, () ->
customService.method(d));
}
}
I get the following error when I run the test
Expected exception.CustomException to be thrown, but nothing was thrown..
Help would be appreciated.
I also met this same problem, and i find that although i mock objectMapper like "
when(objectMapper.readValue(anyString(), any(TypeReference.class))).thenReturn(xxxx);" but when i invoke the test, the first param of readValue(xx,xx) is null which should be a String object. So, you might want to check readValue method input param again.Hope it will help.
There are still some issues with your example code.
You did not inject the Mock of ObjectMapper into your CustomService class.
As your class under test now has a args constructor, you won't be able to inject the mock into your test. You will need to adjust the constructor to pass the ObjectMapper from the outside or rely on Reflections to place the mock manually.
The general advice would be to pass the ObjectMapper as argument into the construtor. Doing it this way, you won't need to change the final on the field mapper.
private final ApplicationProperties props;
private final ObjectMapper mapper;
public CustomService(ApplicationProperties props, ObjectMapper mapper){
this.props = props;
this.mapper = mapper;
}
You still have not defined the behaviour for the mock when the getTypeFactory() method is invoked. You should get a NullPointerException at this point (if your code actually used that mock). In the example below I replaced this definition by using the RETURNS_DEEP_STUBS option,
which causes mapper.getTypeFactory().constructCollectionType(List.class, String.class) to return a mock of CollectionType.
The mock definition with TypeReference is not required, as it does not match your method parameters which are used when the readValue method is invoked. Instead you will have to work with CollectionType.
As your method under test is void you will have to use the willThrow(...).given(...) syntax instead.
Here an example of a working test:
(Only works for a CustomService class with a no-args constructor)
#ExtendWith(MockitoExtension.class)
public class JacksonTest {
static class CustomException extends Exception {
public CustomException(IOException ex) {
super(ex);
}
}
static class CustomService {
private ObjectMapper mapper = new ObjectMapper();
public void method(String c) throws CustomException {
try {
mapper.readValue(c, mapper.getTypeFactory().constructCollectionType(List.class, String.class));
} catch (IOException ex){
throw new CustomException(ex);
}
}
}
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
ObjectMapper mapper;
#InjectMocks
CustomService customService;
#Test
public void testCustomExceptionIsThrown() throws Exception {
BDDMockito.willThrow(new IOException("This is a test")).given(mapper).readValue(ArgumentMatchers.anyString(), ArgumentMatchers.any(CollectionType.class));
Assertions.assertThrows(CustomException.class, () -> customService.method("x"));
}
}
Dependencies:
testCompile "org.junit.jupiter:junit-jupiter-api:5.5.2"
testCompile "org.junit.jupiter:junit-jupiter-engine:5.5.2"
testCompile "org.mockito:mockito-core:3.0.0"
testCompile "org.mockito:mockito-junit-jupiter:3.0.0"
compile "com.fasterxml.jackson.core:jackson-databind:2.9.9"
I have a implementation class which acts as a rabbitMQ sender class, I am trying to write unit test cases for this, but i am having doubts about mocking rabbitmq template.
This is my sender class code:
#Service
public class Car implements CarDelegate {
#Autowired
private RabbitTemplate rt;
#Value("${exchange}")
private String exchange;
#Value("${queue}")
private String queue;
#Override
public ResponseEntity<String> createCar(String model, String name) {
Car car = new Car();
car.setModel(Model);
car.setName(Name);
String jsonString;
jsonString = new ObjectMapper().writeValueAsString(car);
try {
rt.convertAndSend(exchange, queue, jsonString);
} catch (AmqpException e) {
//to implement
}
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
}
My sender class is also my implementation method.
The test class for it is as below:
#RunWith(MockitoJUnitRunner.class)
public class CarTest {
private Car car;
#Mock
private RabbitTemplate rt;
#Test
public void create_valid() {
Car car = new Car(rt);
car.create("sedan", "arison");
String jsonString = "";
Mockito.doReturn("")
.when(rabbitTemplate.convertAndSend(null, null, jsonString))
.myMethod(Mockito.any(createLeadTest_valid.class));
Mockito.when(rabbitTemplate.convertAndSend(null, null, jsonString)).thenReturn("");
}
}
What is the correct way to mock rabbit template
For your specific case, no need to add behavior to your mock.
public class CarServiceTest {
#Test
public void create_valid() {
RabbitTemplate rt = Mockito.mock(RabbitTemplate.class);
CarService car = new CarService(rt);
ResponseEntity<String> response = car.create("sedan", "arison");
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
FYI, it is not good practice to manipulate ResponseEntity outside an HTTP adapter (typically a bean annotated with #Controller).
And RabbitTemplate#convertAndSend is supposed to provide a conversion mechanism, so you do not have to use Jackson directly.
Hoping this will help you !
I'm working in a spring application and I'm trying to use a service class which works perfectly but not inside a simple class.
I suppose that this has to be with bean injection?? or maybe to access spring application context??
What's the best approach to solve this?
Here's my class:
public class RequestDatosFactura
{
JSONObject request;
private Factura factura;
#Autowired
private BitacoraService bitacoraServ;
public RequestDatosFactura(String req) throws JSONException {
this.request = new JSONObject( req );
this.factura = crearFactura();
}
//methods inside class...
This simple class tries to autowired BitacoraService, but when I instantiate, say for example into a spring controller it does well but the BitacoraService is not working.
Any guide or help will be very appreciated
The solution here is to get the service injected in the controller then pass that instance to your regular class, something like:
#Controller
class YourController {
#Autowired
private BitacoraService bitacoraService;
public void someMethod() {
RequestDatosFactura requestDatosFactura = new RequestDatosFactura(bitacoraService);
// use "requestDatosFactura"
}
}
class RequestDatosFactura {
// ...
private final BitacoraService bitacoraService;
public RequestDatosFactura(final BitacoraService bitacoraService) {
this.bitacoraService = bitacoraService;
}
// ...
}