Same checking logic different exception message - java

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".

Related

How to validate the response of my java service in angular?

I have a Java service that queries the database and returns a list of data which I must show in a table in my front with angular, so I did this method that returns a hash map to know if an error occurred when querying or to know that there is no data in the date range so it returns an error code since I want to validate this code in the front and show a message in my front that there is no data or that an error occurred in addition to showing the
Java Controller
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/consultValues")
public class ValuesController {
#GetMapping
public Map<String, Object> consultValues(
#RequestParam(required = false, value = "startDate") Integer startDate,
#RequestParam(required = false, value = "endDate") Integer endDate) throws Exception {
Map<String, Object> listValues = new HashMap<>();
try {
listValues = valuesService.listValues(startDate, endDate);
} catch (Exception e) {
LOGGER.error("Error in Values ");
throw e;
}
return listValues;
}
}
Java Service
#Override
public Map<String, Object> listValues(Integer startDate, Integer endDate) throws Exception {
Map<String, Object> response = new HashMap<>();
List<ValuesDto> list = new ArrayList<ValuesDto>();
try {
Integer start = startDate;
Integer end = endDate;
list = valuesRepository.findByDates(start, end);
if (list.isEmpty() || list == null) {
LOGGER.error("There is not values");
response.put("Error", 400);
}
} catch (Exception e) {
LOGGER.error("An error ocurred");
response.put("Error", 500);
response.put("error", e.getMessage());
throw e;
}
response.put("success", true);
response.put("data", list);
return response;
}
Now in my front I have this method of my service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {ValoresDto} from '../Models/ValoresDTO';
#Injectable({
providedIn: 'root'
})
export class ConsultValuesService {
constructor(private http: HttpClient) { }
Url = 'http://localhost:8080/consultValues';
consultValues(startDate:any, endDate:any){
return this.http.get<ValuesDTO[]>(this.Url+ `?startDate=${startDate}&endDate=${endDate}`);
}
}
In my Component.ts I have this method but I dont know how to validate the response of my java service, for example if my java service returns a code error 400 means that there is not data and show a message with Swal, if returns 500 ocurred an error and show the message with Swal too, or sucees return the list and fill my table
getValuesDB() {
if (this.valuesForm.valid) {
this.service.consultValues(this.endDate, this.endDate).subscribe({
next: data => {
this.modelConsultValues=data;
},
error: (err) => console.error(err),
complete: () => console.log('Completed')
});
} else {
Swal.fire({
icon: 'error',
text: 'You must select both dates'
})
}
}
anyone helps me please, how can I validate the response of my java service and show the table fill or the messages
This is highly opinionated but I will post a link anyway. class-validator let's you spice up models with decorators and then validate the instances.
https://github.com/typestack/class-validator

How to compare Mono error to a String in Java

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.

why jpa not save data at a time

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)

Error while querying for a column in database using spring

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";
}

Removing/deleting from google datastore using endpoints, illegal arguement exception, delete with non-zero content length not supported

I'm trying to delete objects from the datastore (using cloud endpoints)
I know the connection is valid because I'm pulling/inserting objects with no problem
However when I try to delete using various approaches I get the same exception
java.lang.illegalArgumentException:DELETE with non-zero content length is not supported
approach 1(using the raw datastore service and the key I stored when inserting the item):
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
Approach 2
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
EntityManager mgr = getEntityManager();
RPurchase removed=null;
try {
RPurchase rpurchase = mgr.find(RPurchase.class, k);
mgr.remove(rpurchase);
removed=rpurchase;
} finally {
mgr.close();
}
return removed;
}
Ive also tried various variations with the entity manager and the Id, but all with the same exception
The object that i've passed in does contain the namespace in the account, and it does contain the 'KeytoString' of the key associated with the object
the endpoint is called as it should in an AsyncTask endpoint.removeRPurchase(p).execute();
Any help suggestions are appreciated
Make your API method a POST method like this:
#ApiMethod(name = "removeRPurchase" path = "remove_r_purchase", httpMethod = ApiMethod.HttpMethod.POST)
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
I had the same problem because I was using httpMethod = ApiMethod.HttpMethod.DELETE. The error it gives is correct. Simply change it to a POST and do whatever you want inside that API method like delete entities, return entities, etc.
How about trying out the following :
#ApiMethod(
name = "removeRPurchase",
httpMethod = HttpMethod.DELETE
)
public void removeRPurchase(#Named("id") String id) {
//Now take the id and plugin in your datastore code to retrieve / delete
}

Categories