Java Code to invoke PATCH method from JUnit - spring-rest

I have a simple MyLibraryApplication which is having code to invoke POST(TransactionControllerImpl.issueBookToMember) and PATCH(TransactionControllerImpl.returnBookTransaction) methods. I have referred some links on net and tried my best to write code to invoke PATCH method. The code can be found in TransactionControllerTest(testBookReturnUsingRestTemplate and testBookReturnUsingMockMvc methods). The code for invoking POST is working fine but the code for invoking PATCH is not working. Control never reaches returnBookTransaction inside TransactionControllerImpl.
Error: Invalid PATCH method.
I am looking for code snippet for TransactionControllerTest.testBookReturnUsingRestTemplate and testBookReturnUsingMockMvc methods. Can someone help me in getting this code into proper shape?
package com.mycompany.techtrial;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import com.mycompany.techtrial.Transaction;
public interface TransactionController {
public ResponseEntity<Transaction> issueBookToMember(#RequestBody Map<String, String> params);
public ResponseEntity<Transaction> returnBookTransaction(#PathVariable(name="transaction-id") Long transactionId);
}
/**
*
*/
package com.mycompany.techtrial;
import java.time.LocalDateTime;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class TransactionControllerImpl implements TransactionController{
/*
* PLEASE DO NOT CHANGE SIGNATURE OR METHOD TYPE OF END POINTS
* Example Post Request : { "book":"Java8 Primer","member":"Test 1" }
*/
#PostMapping(path = "/api/transaction")
public ResponseEntity<Transaction> issueBookToMember(#RequestBody Map<String, String> params){
String book = params.get("book");
String member = params.get("member");
Transaction transaction = new Transaction();
transaction.setId(1L);
transaction.setBook(book);
transaction.setMember(member);
transaction.setDateOfIssue(LocalDateTime.now());
transaction.setDateOfReturn(Transaction.getDefaultReturnDate());
return ResponseEntity.ok().body(transaction);
}
/*
* PLEASE DO NOT CHANGE SIGNATURE OR METHOD TYPE OF END POINTS
*/
#PatchMapping(path= "/api/transaction/{transaction-id}/return")
public ResponseEntity<Transaction> returnBookTransaction(#PathVariable(name="transaction-id") Long transactionId){
String book = "Java8 Primer";
String member = "Test 1";
Transaction transaction = new Transaction();
transaction.setId(1L);
transaction.setBook(book);
transaction.setMember(member);
transaction.setDateOfIssue(LocalDateTime.now().minusDays(10));
transaction.setDateOfReturn(LocalDateTime.now());
return ResponseEntity.ok().body(transaction);
}
}
package com.mycompany.techtrial;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class TransactionControllerTest {
MockMvc mockMvc;
#Mock
private TransactionController transactionController;
#Autowired
private TestRestTemplate template;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(transactionController).build();
}
#Test
public void testBookIssue() throws Exception {
HttpEntity<Object> transaction = getHttpEntity(
"{\"book\": \"Java8 Primer\", \"member\": \"Test 1\" }");
ResponseEntity<Transaction> response = template.postForEntity(
"/api/transaction", transaction, Transaction.class);
Assert.assertEquals("Java8 Primer", response.getBody().getBook());
Assert.assertEquals("Test 1", response.getBody().getMember());
Assert.assertEquals(200,response.getStatusCode().value());
}
#Test
public void testBookReturnUsingRestTemplate() throws Exception {
Long transactionId = new Long(1);
HashMap<String,Long> uriVariables = new HashMap<String,Long>();
uriVariables.put("transaction-id", transactionId);
Transaction transaction = template.patchForObject(
"/api/transaction/{transaction-id}/return",null, Transaction.class, uriVariables);
Assert.assertEquals(new Long(1), transaction.getId());
//Assert.assertEquals(200,response.getStatusCode().value());
}
#Test
public void testBookReturnUsingMockMvc() throws Exception {
Long transactionId = new Long(1);
HashMap<String,Long> uriVariables = new HashMap<String,Long>();
uriVariables.put("transaction-id", transactionId);
ResultActions obj = mockMvc.perform( MockMvcRequestBuilders
.patch("/api/transaction/{transaction-id}/return",transactionId)
.content("")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON));
System.out.println(obj.getClass());
HttpStatus status = obj.andReturn().getModelAndView().getStatus();
boolean success = status.is2xxSuccessful();
System.out.println("success="+success);
Assert.assertEquals(new Long(1), transactionId);
//Assert.assertEquals(200,response.getStatusCode().value());
}
private HttpEntity<Object> getHttpEntity(Object body) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new HttpEntity<Object>(body, headers);
}
}
package com.mycompany.techtrial;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Transaction implements Serializable {
private static final long serialVersionUID = 8951221480021840448L;
private static final LocalDateTime defaultReturnDate = LocalDateTime.of(LocalDate.of(2299, 12, 31), LocalTime.of(12, 0, 0));
Long id;
private String book;
private String member;
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public String getMember() {
return member;
}
public void setMember(String member) {
this.member = member;
}
//Date and time of issuance of this book
LocalDateTime dateOfIssue;
//Date and time of return of this book
LocalDateTime dateOfReturn;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public LocalDateTime getDateOfIssue() {
return dateOfIssue;
}
public void setDateOfIssue(LocalDateTime dateOfIssue) {
this.dateOfIssue = dateOfIssue;
}
public LocalDateTime getDateOfReturn() {
return dateOfReturn;
}
public void setDateOfReturn(LocalDateTime dateOfReturn) {
this.dateOfReturn = dateOfReturn;
}
#Override
public String toString() {
return "Transaction [id=" + id + ", book=" + book + ", member=" + member + ", dateOfIssue=" + dateOfIssue + ", dateOfReturn=" + dateOfReturn + "]";
}
//#PrePersist
void preInsert() {
if (this.dateOfReturn == null)
this.dateOfReturn = defaultReturnDate;
}
public static LocalDateTime getDefaultReturnDate() {
return defaultReturnDate;
}
}
package com.mycompany.techtrial;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyLibraryApplication {
public static void main(String[] args) {
SpringApplication.run(MyLibraryApplication.class, args);
}
}

It seems to be a known issue with the RestTemplate default Http client.
RestTemplate bug
A workaround for this would be to use the apache httpcomponents httpclient library in the RestTemplateBuilder.setRequestFactory and pass that in the constructor to TestRestTemplate
After that you can use the exchange method on the TestRestTemplate class and do a PATCH request.
Sample code to create TestRestTemplate:
Supplier<ClientHttpRequestFactory> supplier = () -> {
return new HttpComponentsClientHttpRequestFactory();
};
restTemplateBuilder.requestFactory(supplier);
TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder);
testRestTemplate.exchange("/api/transaction/{transaction-id}/return",HttpMethod.PATCH,null,Transaction.class,uriVariables);

Related

Test a Reactive-Kafka Consumer and Producer Template using embedded kafka + custom serialised

We need an example on how to test ReactiveKafkaConsumerTemplate and ReactiveKafkaProducerTemplate with an embedded-kafka-broker. Thanks.
CORRECT CODE IS HERE AFTR DISCUSSION
You can have your custom de-serializer accordingly to use custom ReactiveKafkaConsumerTemplate
Custom Serialiser:
import org.apache.kafka.common.serialization.Serializer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class EmployeeSerializer implements Serializer<Employee> {
#Override
public byte[] serialize(String topic, Employee data) {
byte[] rb = null;
ObjectMapper mapper = new ObjectMapper();
try {
rb = mapper.writeValueAsString(data).getBytes();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return rb;
}
}
Use it part of embedded-kfka-reactive test:
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.connect.json.JsonSerializer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.kafka.core.reactive.ReactiveKafkaProducerTemplate;
import org.springframework.kafka.support.converter.MessagingMessageConverter;
import org.springframework.kafka.test.condition.EmbeddedKafkaCondition;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import reactor.kafka.sender.SenderOptions;
import reactor.kafka.sender.SenderRecord;
import reactor.test.StepVerifier;
#EmbeddedKafka(topics = EmbeddedKafkareactiveTest.REACTIVE_INT_KEY_TOPIC,
brokerProperties = { "transaction.state.log.replication.factor=1", "transaction.state.log.min.isr=1" })
public class EmbeddedKafkareactiveTest {
public static final String REACTIVE_INT_KEY_TOPIC = "reactive_int_key_topic";
private static final Integer DEFAULT_KEY = 1;
private static final String DEFAULT_VERIFY_TIMEOUT = null;
private ReactiveKafkaProducerTemplate<Integer, Employee> reactiveKafkaProducerTemplate;
#BeforeEach
public void setUp() {
reactiveKafkaProducerTemplate = new ReactiveKafkaProducerTemplate<>(setupSenderOptionsWithDefaultTopic(),
new MessagingMessageConverter());
}
private SenderOptions<Integer, Employee> setupSenderOptionsWithDefaultTopic() {
Map<String, Object> senderProps = KafkaTestUtils
.producerProps(EmbeddedKafkaCondition.getBroker().getBrokersAsString());
SenderOptions<Integer, Employee> senderOptions = SenderOptions.create(senderProps);
senderOptions = senderOptions.producerProperty(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "reactive.transaction")
.producerProperty(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)
.producerProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class.getName())
;
return senderOptions;
}
#Test
public void test_When_Publish() {
Employee employee = new Employee();
ProducerRecord<Integer, Employee> producerRecord = new ProducerRecord<Integer, Employee>(REACTIVE_INT_KEY_TOPIC, DEFAULT_KEY, employee);
StepVerifier.create(reactiveKafkaProducerTemplate.send(producerRecord)
.then())
.expectComplete()
.verify();
}
#AfterEach
public void tearDown() {
reactiveKafkaProducerTemplate.close();
}
}
The tests in the framework use an embedded kafka broker.
https://github.com/spring-projects/spring-kafka/tree/main/spring-kafka/src/test/java/org/springframework/kafka/core/reactive
#EmbeddedKafka(topics = ReactiveKafkaProducerTemplateIntegrationTests.REACTIVE_INT_KEY_TOPIC, partitions = 2)
public class ReactiveKafkaProducerTemplateIntegrationTests {
...
added correct serialised with a non-transactional producer. please see the code on top of this page for the answer.

Spring webflux - ServerWebExchangeDecorator code is not executed when an exception is thrown

I have a Webflux application, where I have a ServerWebExchangeDecorator that decorates the request and responses. I have overrides to do some logging and then call the super methods.
This is what I have in code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebExchangeDecorator;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
#Component
public class LoggingWebFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(decorate(exchange));
}
private ServerWebExchange decorate(ServerWebExchange exchange) {
final ServerHttpRequest decoratedRequest = new LoggingServerHttpRequestDecorator(exchange.getRequest());
final ServerHttpResponse decoratedResponse = new LoggingServerHttpResponseDecorator(exchange.getResponse());
return new ServerWebExchangeDecorator(exchange) {
#Override
public ServerHttpRequest getRequest() {
return decoratedRequest;
}
#Override
public ServerHttpResponse getResponse() {
return decoratedResponse;
}
};
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import reactor.core.publisher.Flux;
public class LoggingServerHttpRequestDecorator extends ServerHttpRequestDecorator {
private static final Logger logger = LoggerFactory.getLogger(LoggingServerHttpRequestDecorator.class);
public LoggingServerHttpRequestDecorator(ServerHttpRequest delegate) {
super(delegate);
}
#Override
public Flux<DataBuffer> getBody() {
logger.info("getBody method");
return super.getBody();
}
}
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import reactor.core.publisher.Mono;
public class LoggingServerHttpResponseDecorator extends ServerHttpResponseDecorator {
private static final Logger logger = LoggerFactory.getLogger(LoggingServerHttpResponseDecorator.class);
public LoggingServerHttpResponseDecorator(ServerHttpResponse delegate) {
super(delegate);
}
#Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
logger.info("writeWith method");//THIS LINE IS NOT EXECUTED WHEN AN EXCEPTION IS THROWN
return super.writeWith(body);
}
#Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
logger.info("writeAndFlushWith method");
return super.writeAndFlushWith(body);
}
}
When I do a happy path with a POST request, this works fine, but when an exception is thrown, the Response Decorator is omitted and my custom code is not being executed.
This is a controller code to replicate the issue:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#RestController
#RequestMapping("/decorator-demo")
public class DecoratorDemoController {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(DecoratorDemoController.class);
#PostMapping(produces = MediaType.APPLICATION_STREAM_JSON_VALUE, consumes = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Mono<ResponseEntity<String>> postData(#RequestBody String id) {
logger.info("attempting to post the data");
if(id.length() == 1){
Mono<String> created = Mono.just(id);
return created.flatMap(vo -> Mono.just(ResponseEntity.status(HttpStatus.CREATED).body(vo)));
}
throw new IllegalArgumentException("String length must be 1");
}
}
When I post a single character, I have the logs I am expecting:
LoggingServerHttpRequestDecorator : getBody method
DecoratorDemoController : attempting to post the data
LoggingServerHttpResponseDecorator : writeWith method
But when I post more than one character, this is the logs I am having:
LoggingServerHttpRequestDecorator : getBody method
DecoratorDemoController : attempting to post the data
AbstractErrorWebExceptionHandler : [0b933716] 500 Server Error for HTTP POST "/decorator-demo"
Am I doing something wrong, or missing something?
Try this
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#Component
public class ResponseInterceptorFilter implements Ordered, GlobalFilter {
private static final Logger log = LoggerFactory.getLogger(ResponseInterceptorFilter.class);
public ResponseInterceptorFilter(SqsPublisher sqsPublisher) {
this.sqsPublisher = sqsPublisher;
}
#Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
DataBufferFactory dataBufferFactory = response.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {
#Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (!(body instanceof Flux)) {
return super.writeWith(body);
}
Flux<? extends DataBuffer> flux = (Flux<? extends DataBuffer>) body;
return super.writeWith(flux.buffer().map(dataBuffers -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
dataBuffers.forEach(buffer -> {
// three byte copies here
byte[] array = new byte[buffer.readableByteCount()];
buffer.read(array);
try {
outputStream.write(array);
} catch (IOException e) {
// TODO: need catch?
}
DataBufferUtils.release(buffer);
});
byte[] write = outputStream.toByteArray();
String responseBody = new String(write);
log.debug("Response ----> {}", responseBody);
response.getHeaders().setContentLength(write.length);
return dataBufferFactory.wrap(write);
}));
}
};
ServerWebExchange serverWebExchange = exchange.mutate().response(decoratedResponse).build();
return chain.filter(serverWebExchange);
}
#Override
public int getOrder() {
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; // this is important
}
}

month is set to january in oracle 11g irresptive of any month

I know its a bit weird question. I am passing date dd-mm-yyyy format from my UI and storing that into oracle 11g. but strange thing happened that it is storing it as JAN month only i.e if I pass 16-10-1992 or 10-03-1992 it is storing it as a 16-JAN-1992 way only. please let me know what silly thing I missed out?
Here's my HibernateUtil.java
package assignment.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.springframework.stereotype.Component;
import assignment.service.UserEntity;
#Component
public class HibernateUtil {
private static SessionFactory sessionFactorty=null;
public static SessionFactory getSessionFactory(){
if(sessionFactorty==null){
System.out.println("inside hibernate Util");
Configuration configuration=new Configuration();
configuration.addAnnotatedClass(UserEntity.class);
configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
configuration.setProperty("hibernate.connection.driver_class", "oracle.jdbc.driver.OracleDriver");
configuration.setProperty("hibernate.connection.username", "myDb");
configuration.setProperty("hibernate.connection.password", "Vihang616");
configuration.setProperty("hibernate.connection.url", "jdbc:oracle:thin:#127.0.0.1:1521:myDb");
/*SchemaExport schemaExport=new SchemaExport(configuration);
schemaExport.create(true, true);*/
StandardServiceRegistryBuilder srb=new StandardServiceRegistryBuilder();
srb.applySettings(configuration.getProperties());
ServiceRegistry serviceRegistry=srb.build();
sessionFactorty=configuration.buildSessionFactory(serviceRegistry);
}
return sessionFactorty;
}
public static void shutDown(){
if(sessionFactorty!=null)
sessionFactorty.close();
}
}
Here's my USerService.java
package assignment.service;
import org.hibernate.Session;
import org.springframework.stereotype.Component;
import assignment.model.User;
import assignment.util.HibernateUtil;
import assignment.util.ServiceUtil;
#Component
public class UserService {
public Integer saveUser(User user) {
Session session=HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
UserEntity userEntity=new UserEntity();
userEntity.setDob(ServiceUtil.stringToDateConverter(user.getDob()));
userEntity.setEmail(user.getEmail());
userEntity.setUserName(user.getUserName());
session.save(userEntity);
session.getTransaction().commit();
System.out.println("ID:"+userEntity.getUserId());
session.disconnect();
HibernateUtil.shutDown();
return userEntity.getUserId();
}
}
Here's my SerivceUtl.java
package assignment.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ServiceUtil {
public static Date stringToDateConverter(String string){
SimpleDateFormat sdf=new SimpleDateFormat("dd-mm-yyyy");
System.out.println("dob:"+string);
Date date=new Date();
try {
date=sdf.parse(string);
} catch (ParseException e) {
System.out.println("exception in parsing date");
e.printStackTrace();
}
return date;
}
}
Here's My Entity class
package assignment.service;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name="UserDb")
public class UserEntity implements Serializable {
private static final long serialVersionUID = -6620152467355557520L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;
#Column(nullable=false)
private String userName;
#Column(nullable=false)
private String email;
#Column(nullable=false)
#Temporal(TemporalType.DATE)
private Date dob;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getDob() {
return dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}

Mockito testing service layer

I'm new to Mockito and trying to test my service layer. My DAO layer is #Autowired in service and Hibernate is also autowired. Hibernate is not loading while testing. I always get NullPointerException. Here is my code:
EmployeeService (Interface)
package com.spring.crud.service;
import java.util.List;
import com.spring.crud.entity.Employee;
public interface EmployeeService {
Employee save(Employee employee);
boolean update(Employee employee);
Employee find(Integer id);
List<Employee> getEmployees();
boolean remove(Integer id);
}
EmployeeServiceImpl (Class)
package com.spring.crud.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.entity.Employee;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeDAO dao;
public Employee save(Employee employee) {
return dao.save(employee);
}
public boolean update(Employee employee) {
return dao.update(employee);
}
public Employee find(Integer id) {
return dao.find(id);
}
public List<Employee> getEmployees() {
return dao.getEmployees();
}
public boolean remove(Integer id) {
return dao.remove(id);
}
}
EmployeeDAO (Interface)
package com.spring.crud.dao;
import java.util.List;
import com.spring.crud.entity.Employee;
public interface EmployeeDAO {
Employee save(Employee employee);
boolean update(Employee employee);
Employee find(Integer id);
List<Employee> getEmployees();
boolean remove(Integer id);
}
EmployeeDAOImpl (Class)
package com.spring.crud.dao;
import java.util.List;
import javax.transaction.Transactional;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;
import com.spring.crud.entity.Employee;
#Transactional
#Repository
public class EmployeeDAOImpl extends HibernateUtil implements EmployeeDAO{
public Employee save(Employee employee) {
Session session = getCurrentSession();
session.save(employee);
return employee;
}
public boolean update(Employee employee) {
Session session = getCurrentSession();
session.update(employee);
return false;
}
public Employee find(Integer id) {
Session session = getCurrentSession();
Employee employee = (Employee)session.get(Employee.class, id);
return employee;
}
public List<Employee> getEmployees() {
Session session = getCurrentSession();
Query query = session.createQuery("from Employee");
#SuppressWarnings("unchecked")
List<Employee> employees = (List<Employee>)query.list();
return employees;
}
public boolean remove(Integer id) {
Session session = getCurrentSession();
Employee employee = (Employee)session.get(Employee.class, id);
if(employee!=null){
session.delete(employee);
return true;
}
return false;
}
}
HibernateUtil
package com.spring.crud.dao;
import javax.annotation.PostConstruct;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class HibernateUtil extends HibernateDaoSupport{
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void init() {
setSessionFactory(sessionFactory);
}
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
EmployeeServiceTest (Test class)
package com.spring.crud.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.test.context.ContextConfiguration;
import com.spring.crud.config.WebConfig;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.dao.EmployeeDAOImpl;
import com.spring.crud.entity.Employee;
import com.spring.crud.service.EmployeeService;
import com.spring.crud.service.EmployeeServiceImpl;
#ContextConfiguration(classes = {WebConfig.class})
public class EmployeeServiceTest {
private EmployeeDAO employeeDAO;
private EmployeeService employeeService = new EmployeeServiceImpl();
#Spy
List<Employee> employees = new ArrayList<Employee>();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
employeeDAO = mock(EmployeeDAOImpl.class);
}
#Test
public void listEmployees() {
}
#Test
public void create() {
Employee employee = new Employee();
employee.setDateOfBirth(new Date());
employee.setGender("male");
employee.setName("Ashutosh");
when(employeeDAO.save(any(Employee.class)))
.thenAnswer(new Answer<Employee>() {
public Employee answer(InvocationOnMock invocation) throws Throwable {
Employee employee = (Employee) invocation.getArguments()[0];
employee.setId(1);
return employee;
}
});
assertNull(employee.getId());
employee = employeeService.save(employee);
assertNotNull(employee.getId());
assertTrue(employee.getId()>0);
}
#Test
public void edit() {
}
#Test
public void update() {
}
#Test
public void remove() {
}
}
I can't find much on this on the internet.
Just because you create a mock employee DAO in your test doesn't mean that your service will use it. It won't. When you do
new EmployeeServiceImpl();
you create an instance of the service, and its DAO field is left uninitialized (so null).
Use constructor injection, and pass the mock DAO to the service constructor:
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDAO dao;
#Autowired
public EmployeeServiceImpl(EmployeeDAO dao) {
this.dao = dao;
}
...
}
And/or at least use Mockito annotations correctly:
#Mock
private EmployeeDAO employeeDAO;
#InjectMocks
private EmployeeServiceImpl employeeService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
OK, I found some fixes and now the test runs.
First, I fixed the HibernateUtil
package com.spring.crud.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class HibernateUtil{
#Autowired
private SessionFactory sessionFactory;
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
This is the EmployeeServiceTest class
package com.spring.crud.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.test.context.ContextConfiguration;
import com.spring.crud.config.WebConfig;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.entity.Employee;
import com.spring.crud.service.EmployeeServiceImpl;
#ContextConfiguration(classes = {WebConfig.class})
public class EmployeeServiceTest {
#Mock
private EmployeeDAO employeeDAO;
#InjectMocks
private EmployeeServiceImpl employeeService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void listEmployees() {
}
#Test
public void create() {
Employee employee = new Employee();
employee.setDateOfBirth(new Date());
employee.setGender("male");
employee.setName("Ashutosh");
when(employeeDAO.save(any(Employee.class)))
.thenAnswer(new Answer<Employee>() {
public Employee answer(InvocationOnMock invocation) throws Throwable {
Employee employee = (Employee) invocation.getArguments()[0];
employee.setId(10);
return employee;
}
});
assertNull(employee.getId());
employee = employeeService.save(employee);
System.out.println("Id = " + employee.getId());
assertNotNull(employee);
assertEquals((Integer)10, (Integer)employee.getId());
}
#Test
public void edit() {
}
#Test
public void update() {
}
#Test
public void remove() {
}
}

JAXB Marshal and Unmarshal Map to/from <key>value</key>

I'm trying to marshal and unmarshal Map to/from value pairs. I can marshal the object successfully, however, I cannot unmarshal it from the xml. The unmarshal result is the key exist in the Map, however, its value is null.
Here's the model I want to marshal and unmarshal:
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement(name="TestModel")
#XmlAccessorType(XmlAccessType.FIELD)
public class TestModel {
#XmlElement(name="Name")
private String name;
#XmlJavaTypeAdapter(MapAdapter.class)
private Map<String, String> metadata;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
}
I create a Map Adapter for marshal and unmarshal like below:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;
import org.w3c.dom.Element;
public class MapAdapter extends XmlAdapter<MapWrapper, Map<String, String>> {
#Override
public MapWrapper marshal(Map<String, String> m) throws Exception {
MapWrapper wrapper = new MapWrapper();
List<JAXBElement<String>> elements = new ArrayList<JAXBElement<String>>();
if (m != null && !m.isEmpty()) {
for (Entry<String, String> property : m.entrySet()) {
elements.add(new JAXBElement<String>(new QName(property.getKey()),
String.class, property.getValue().toString()));
}
}
wrapper.elements = elements;
return wrapper;
}
#Override
public Map<String, String> unmarshal(MapWrapper v) throws Exception {
Map<String, String> map = new HashMap<String, String>();
if (v != null && v.elements != null && !v.elements.isEmpty()) {
for (Object object : v.elements) {
Element element = (Element) object;
map.put(element.getNodeName(), element.getNodeValue());
}
}
return map;
}
}
class MapWrapper {
#XmlAnyElement(lax=true)
protected List<JAXBElement<String>> elements;
}
And the below class can test the marshal and unmarshal of the above model:
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class TestEntry {
public static void main(String[] args) throws JAXBException {
testMarshal();
testUnmarshal();
}
public static void testMarshal() throws JAXBException {
Map<String, String> metadata = new HashMap<String, String>();
metadata.put("category", "test");
metadata.put("creation", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
TestModel model = new TestModel();
model.setMetadata(metadata);
model.setName("TESTMODEL");
marshal(model, System.out);
}
public static void testUnmarshal() throws JAXBException {
String model = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>"
+ "<TestModel>"
+ "<Name>TESTMODEL</Name>"
+ "<metadata>"
+ "<category>test</category>"
+ "<creation>2015-09-29</creation>"
+ "</metadata>"
+ "</TestModel>";
TestModel result = unmarshal(new ByteArrayInputStream(model.getBytes()), TestModel.class);
System.out.println("name=" + result.getName());
for (String key : result.getMetadata().keySet()) {
System.out.println(key + ", " + result.getMetadata().get(key));
}
}
public static <T> void marshal(T cls, OutputStream os) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(cls.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(cls, os);
}
#SuppressWarnings("unchecked")
public static <T> T unmarshal(InputStream is, Class<T> cls)
throws JAXBException {
JAXBContext context = JAXBContext.newInstance(cls);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (T) unmarshaller.unmarshal(is);
}
}
It seems that, the map only contains the key with 'null' value when invoke 'public Map unmarshal(MapWrapper v) throws Exception'.
And I also find a similar question about this issue "JAXB: how to marshall map into <key>value</key>", however, it didn't solve the unmarshal issue?
A very small correction:
map.put(element.getNodeName(), element.getTextContent());

Resources