I have a method something like this :
public Mono<SomeDTO> DoAction(SomeDTO someDTOObject) {
return findUser(someDTOObject.getUsername())
.flatMap(existingUser -> {
Update update = new Update();
return mongoTemplate.upsert(
Query.query(Criteria.where("username").is(someDTOObject.getUsername())),
update,
SomeDTO.class,
COLLECTION_NAME);
}).switchIfEmpty(
Mono.defer(() -> {
return Mono.error(new Exception("User Name doesn't exist."));
})
);
}
For this, I have wriiten a testcase like this to test exception :
#Test
public void DoAction_TestException() {
SomeDTO someDTOObject = databaseUtil.SomeDTOMock;
Query query = Query.query(Criteria.where("username").regex("^"+userId+"$","i"));
doReturn(Mono.empty()).when(mongoTemplate).findOne(query,
SomeDTO.class, "COLLECTION_NAME");
try {
SomeDTO someDTOObjectResult = mongoImpl.DoAction(someDTOObject).block();
}
catch (Exception e) {
String expected = "User Name doesn't exist.";
String result = e.getMessage().toString(); /////// this value during debugging is "java.lang.Exception:User Name doesn't exist. "
assertEquals(expected,result);
}
}
When I run the above code , the assert is failing becuase variable result has extra string along with it. How can I remove java.lang.Exception from the result ?
I dont want to use any string functions to remove part of string.ANy help would be very helpful.
If you're already in a catch clause, you're not dealing with Mono anymore.
In debugging you're checking e.toString(), which will be "java.lang.Exception:User Name doesn't exist. ".
But try to check behavior in a more isolated way.
public static void main(String[] args) {
Exception exception = new Exception("User Name doesn't exist.");
try {
throw exception;
} catch (Exception e) {
System.out.println("getMessage: " +e.getMessage());
System.out.println("toString: " + e.toString());
}
}
In this case e.getMessage() will print as expected User Name doesn't exist.
Eugene's answer is already showing you the correct way.
Alternate Solution #1:
Create a specific Exception class: EntityNotFoundException extends IOException or UsernameNotFoundException extends IOException and test if your result is an instance of that class.
Alternate Solution #2:
Extend your expected String expected to the String you really get.
Alternate Solution #3:
(I do not know Mono, so IF:) If Mono wraps up the Exception into another exception, you probably can reach that original exception by using e.getCause: Change your line String result = e.getMessage().toString(); to String result = e.getCause().getMessage();.
To help us find that out, simply add the line e.printStackTrace(); right after your line String expected = "User Name doesn't exist.";, and then show us what error message was printed. From there on we can help further, if the other solutions have not helped yet.
Related
I have a web service accept two different interfaces(i.e. A and B) and there are some common fields which share same checking logic. However different error message have to be returned if the checking is failed and point out which field in the request body is invalid. Is there any way to reduce the code duplication for the checking logic.
Interface A may be accepting json as the request body,
{
"companyAClient":{
"id": 12345,
"name": "ABC Limited",
...
},
...
}
Interface B may be accepting xml as the request body with completly different structure compare to interface A
<MSG>
...
<MSG.BODY>
...
<COMPANY>
<CLIENT>
<ID>23456</ID>
<NAME>XYZ Limited</NAME>
...
</CLIENT>
...
</COMPANY>
...
</MSG.BODY>
</MSG>
private checkInterfaceA(String clientId, String clientName, other variables...) {
Long id;
try {
id = Long.parse(clientId);
} catch (Exception e) {
throw new InterfaceException("[EOS_E01] 'companyAClient.id' is empty.");
}
if(*clientId not exist in DB*) {
throw new InterfaceException("[EOS_E02] 'companyAClient.id' not match with DB records.");
}
if(*clientName.toUpperCase() not found in DB*) {
throw new InterfaceException("[EOS_E03] 'companyAClient.name' not match with DB records.");
}
Other checking...
}
private checkInterfaceB(String clientId, String clientName, other variables...) {
Long id;
try {
id = Long.parse(clientId);
} catch (Exception e) {
throw new InterfaceException("[E_XML_001] Parse Client ID error. Please check '/MSG/MSG.BODY/COMPANY/CLIENT/ID'.");
}
if(*clientId not exist in DB*) {
throw new InterfaceException("[E_XML_002] Client ID not found error. Please check '/MSG/MSG.BODY/COMPANY/CLIENT/ID'");
}
if(*clientName.toUpperCase() not found in DB*) {
throw new InterfaceException("[E_XML_003] Client name not found error. Please check '/MSG/MSG.BODY/COMPANY/CLIENT/NAME'");
}
Other checking...
}
You could make a method where you pass the text in.
private checkInterface0(String clientId, String msgTemplate) {
Long id;
try {
id = Long.parse(clientId);
} catch (Exception e) {
throw new InterfaceException(msgTemplate);
}
if(*clientId not exist in DB*) {
throw new InterfaceException(msgTemplate);
}
}
You might want to treat the template as either a filler (throw new InterfaceException("Parse ID error in " + template);) or by using string.format: throw new InterfaceException(String.format(template, "Parse ID error"). The parameter would be something like "%s in interface A".
For below method i am writing JUnit testcase for sonarqube coverage.
#Transformer
public Object errorUnWrapper(Message<?> message) {
String value = "";
try {
if (!errorFlag) {
value = errorTransform(ESBConstants.SYSTEMERRCODE, ESBConstants.SYSTEMERROR, ESBConstants.SYSTEMTEXT);
} else {
value = getbankholiday.getErrorMessage();
}
} catch (Exception e) {
getbankholiday.getE2EObject().logMessage("3005", "Error Occurred in error unwrapper");
value = ESBConstants.SYSTEMERRORXML;
}
MessageHeaders headers = ((MessagingException) message.getPayload()).getFailedMessage().getHeaders();
return MessageBuilder.withPayload(value).copyHeaders(message.getHeaders())
.copyHeadersIfAbsent(headers).setHeader(ESBConstants.CONTENTTYPE, ESBConstants.CONTENTVALUE)
.build();
}
JUnit testcase:
#Test
void testErrorUnWrapper() throws IOException {
String xml = FileUtils.readFileToString(new File("src/test/resources/JunitTestCases/input/TC02_wltRequest.xml"),
"UTF-8");
test = MessageBuilder.withPayload(xml).build();
errorTransform.errorUnWrapper(test);
Assertions.assertTrue(true);
}
but, unable to mock or test the below line in JUnit testcase.
MessageHeaders headers = ((MessagingException) message.getPayload()).getFailedMessage().getHeaders();
Exception:
java.lang.ClassCastException: java.lang.String cannot be cast to org.springframework.messaging.MessagingException
at com.bt.or.esb.exceptions.ErrorTransform.errorUnWrapper(ErrorTransform.java:75)
at com.bt.or.esb.exceptions.ErrorTransformTest.testErrorUnWrapper(ErrorTransformTest.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Your productive code
(MessagingException) message.getPayload()
means you expect message.payload to be a MessagingException. But in your test, you create
MessageBuilder.withPayload(xml).build()
so payload will be a string. You need to build a message with a MessagingException as payload.
This usually means you need to refactor.
except for value everything else is common in if else and catch blocks
why don't you compute value first and then execute below two lines?
MessageHeaders headers = ((MessagingException) message.getPayload()).getFailedMessage().getHeaders();
return MessageBuilder.withPayload(value).copyHeaders(message.getHeaders()).copyHeadersIfAbsent(headers)
.setHeader(ESBConstants.CONTENTTYPE, ESBConstants.CONTENTVALUE).build();
i want save data and check the data after call save method
but the value is not present in same request
i have two method depend each other
the two function communcation with each other by kafka
the first method save the data and after save using jpa call second method
find the recourd from database using jpa
and check the instanse using isPresent()
but in the second method i cant find the data save
but after this request i can find data
return exciption NoSuchElement
Try out several ways like:
1-use flush and saveAndFlush
2-sleep method 10000 milsec
3-use entityManger with #Transactional
but all of them not correct
i want showing you my two method from code:
i have producer and consumer
and this is SaveOrder method (first method):
note : where in the first method have all ways i used
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void saveOrder(Long branchId,AscOrderDTO ascOrderDTO) throws Exception {
ascOrderDTO.validation();
if (ascOrderDTO.getId() == null) {
ascOrderDTO.setCreationDate(Instant.now());
ascOrderDTO.setCreatedBy(SecurityUtils.getCurrentUserLogin().get());
//add user
ascOrderDTO.setStoreId(null);
String currentUser=SecurityUtils.getCurrentUserLogin().get();
AppUser appUser=appUserRepository.findByLogin(currentUser);
ascOrderDTO.setAppUserId(appUser.getId());
}
log.debug("Request to save AscOrder : {}", ascOrderDTO);
AscOrder ascOrder = ascOrderMapper.toEntity(ascOrderDTO);
//send notify to branch
if(!branchService.orderOk())
{
throw new BadRequestAlertException("branch not accept order", "check order with branch", "branch");
}
ascOrder = ascOrderRepository.save(ascOrder);
/*
* log.debug("start sleep"); Thread.sleep(10000); log.debug("end sleep");
*/
entityManager.setFlushMode(FlushModeType.AUTO);
entityManager.flush();
entityManager.clear();
//ascOrderRepository.flush();
try {
producerOrder.addOrder(branchId,ascOrder.getId(),true);
stateMachineHandler.stateMachine(OrderEvent.EMPTY, ascOrder.getId());
stateMachineHandler.handling(ascOrder.getId());
//return ascOrderMapper.toDto(ascOrder);
}
catch (Exception e) {
// TODO: handle exception
ascOrderRepository.delete(ascOrder);
throw new BadRequestAlertException("cannot deliver order to Branch", "try agine", "Try!");
}
}
in this code go to producer :
producerOrder.addOrder(branchId,ascOrder.getId(),true);
and this is my producer:
public void addOrder(Long branchId, Long orderId, Boolean isAccept) throws Exception {
ObjectMapper obj = new ObjectMapper();
try {
Map<String, String> map = new HashMap<>();
map.put("branchId", branchId.toString());
map.put("orderId", orderId.toString());
map.put("isAccept", isAccept.toString());
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
and in this code go to consumer:
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
this is my consumer:
#KafkaListener(topics = "orderone", groupId = "groupId")
public void processAddOrder(String mapping) throws Exception {
try {
log.debug("i am in consumer add Order");
ObjectMapper mapper = new ObjectMapper(); Map<String, String> result = mapper.readValue(mapping,
HashMap.class);
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
log.debug(result.toString());
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
**and this code go to AcceptOrder (second method) : **
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
this is my second method :
public AscOrderDTO acceptOrder(Long branchId, Long orderId, boolean acceptable) throws Exception {
ascOrderRepository.flush();
try {
if (branchId == null || orderId == null || !acceptable) {
throw new BadRequestAlertException("URl invalid query", "URL", "Check your Input");
}
if (!branchRepository.findById(branchId).isPresent() || !ascOrderRepository.findById(orderId).isPresent()) {
throw new BadRequestAlertException("cannot find branch or Order", "URL", "Check your Input");
}
/*
* if (acceptable) { ascOrder.setStatus(OrderStatus.PREPARING); } else {
* ascOrder.setStatus(OrderStatus.PENDING); }
*/
Branch branch = branchRepository.findById(branchId).get();
AscOrder ascOrder = ascOrderRepository.findById(orderId).get();
ascOrder.setDiscount(50.0);
branch.addOrders(ascOrder);
branchRepository.save(branch);
log.debug("///////////////////////////////Add order sucess////////////////////////////////////////////////");
return ascOrderMapper.toDto(ascOrder);
} catch (Exception e) {
// TODO: handle exception
throw new Exception(e.getMessage());
}
}
Adding Thread.sleep() inside saveOrder makes no sense.
processAddOrder executes on a completely different thread, with a completely different persistence context. All the while, your transaction from saveOrder might still be ongoing, with none of the changes made visible to other transactions.
Try splitting saveOrder into a transactional method and sending the notification, making sure that the transaction ends before the event handling has a chance to take place.
(Note that this approach introduces at-most-once semantics. You have been warned)
I am trying to query an entire column data for eg:
SELECT USER_USERNAME FROM xxxx WHERE USER_USERNAME=?
I'm getting error
org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
My Dao
#Override
public String getAllUsers(UserRegistration uname) {
System.out.println(uname.getUserName());
return template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
}
I'm injecting the properties through xml file.
my controller
#RequestMapping(method = RequestMethod.POST,value = "/checkUserName", headers = "Accept=application/json")
public org.weber.nag.model.UserRegistration checkUserName(#RequestBody org.weber.nag.model.UserRegistration userReg) {
userDao.getAllUsers(userReg);
return userReg;
}
So from the above when i am trying to pass the username from postman it takes the values to controller and from there I'm passing it to my dao to compare whether the name exits or not.The name successfully reaches my dao but I get an error.
So I tried to catch the exception
#Override
public String getAllUsers(UserRegistration uname) {
System.out.println(uname.getUserName());
try {
return template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
} catch (EmptyResultDataAccessException e) {
System.out.println("uname already exists");
return "user exists";
}
}
But every time it prints
"uname already exists"
irrespective of the username given whether it is there in db or not.
In JdbcTemplate , queryForInt, queryForLong, queryForObject all such methods expects that executed query will return one and only one row.
If you get no rows that will result in EmptyResultDataAccessException.
From the javadoc of EmptyResultDataAccessException
Data access exception thrown when a result was expected to have at
least one row (or element) but zero rows (or elements) were actually
returned.
Make sure the query you are using should return only one row.
If at all it is not possible then use query method instead of queryForObject.
Tip: To debug this, run the same query in an SQL IDE directly.
#Override
public String getAllUsers(UserRegistration uname) {
try {
template.queryForObject(GET_USER_USERNAME, new Object[] { uname.getUserName() },
new BeanPropertyRowMapper<String>(String.class));
System.out.println("uname exists");
return "user name is NOT available.";
} catch (EmptyResultDataAccessException e) {
System.out.println("uname do not exists");
}
return "user is available";
}
As the title says, I need a way(no matter if its complicated or not) to create a getData() method that would send request packet to the server > receive the message I already have the system setup but I have a problem with it that I only get the result in PluginMessageReceiveEvent Here's my code with explanations:
public String requestData(String path) {
SocketUtils.sendData("REQUEST|" + p.getPlayer().getUniqueId() + "|" + path, "playerconfig", "BUNGEE");
return /*Need to get data from the plugin message to here*/;
}
#EventHandler
public void onPluginMessageReceive(PluginMessageReceiveEvent e) {
if (e.getChannel().equalsIgnoreCase("playerconfig")) {
String[] args = e.getMessage().split("\\|");
String uuid = args[0];
String path = args[1];//Maybe a HashMap<Path, Data> but that would make the requestData() result return null because you don't get the data instantly.
String data = args[2].replace("_", " ");
if (uuid.equals(p.getPlayer().getUniqueId() + "")) {
return data; //I need to get this result on request data method.
}
}
}
A simple solution is to wait on a lock in the requestData and notify that lock in onPluginMessageReceive. Something like this:
synchronized(this) {
wait();
}
And in your receive method:
synchronized(this) {
notifyAll();
}
Make the data a member field of the class.
Look out for exception handling and syntax errors.