Entity from Optional Object (Java 8) - java

I am having some issue while trying to pull an entity out of an ArrayList that holds and Optional. When I do a breakpoint I get the return below the code. I know I am close but lack the knowledge on how to pull the GrandClientDataCore#9463 out of the data being returned to me.
Edited to add the previous line before the for loop.
Error occured: java.util.Optional cannot be cast to net.glmhc.dmhwebservices.entities.GrandClientDataCores.
List<GrandClientDataCores> grandClientDataCoresList = getGrandClientDataCoreList(submitMode, grandClientDataCoreId);
for (GrandClientDataCores grandClientDataCores : grandClientDataCoresList) {
CDCPAErrors request = new CDCPAErrors();
request.setI(this.service.getRequestInfo(grandClientDataCores, submitMode, staff));
logToFile(outDir, String.format("req_%s.xml", new Object[] {grandClientDataCores}), request);
CDCPAErrorsResponse response = (CDCPAErrorsResponse)
getWebServiceTemplate().marshalSendAndReceive(getWebServiceUri(), request,
(WebServiceMessageCallback) new SoapActionCallback("http://tempuri.org/CDCPAErrors"));
logToFile(outDir, String.format("res_%s.xml", new Object[] {grandClientDataCoreId}), response);
DmhServicesCdcResponse responseObj = getResponse(submitMode, response);
this.service.saveResponse(grandClientDataCores, submitMode, responseObj, staff);
responses.add(responseObj);
}
This is the getGrandClientDataCoreList
protected List<GrandClientDataCores> getGrandClientDataCoreList(SubmitMode submitMode, String grandClientDataCore) throws Exception {
List<GrandClientDataCores> grandClientDataCoresList;
try {
grandClientDataCoresList = (List<GrandClientDataCores>) this.service.getGrandClientDataCoreList(submitMode, grandClientDataCore);
} catch ( Exception ex) {
throw new Exception(ex);
}
if (grandClientDataCore == null || grandClientDataCore.isEmpty()) {
throw new NoDataException("No CDC record to validate.");
}
return grandClientDataCoresList;
}

You have to invoke get() on the optional to retrieve its value. You cannot just cast Optional<T> to something else. According to the debug image, the declaration of grandClientDataCoresList looked like this:
List<Optional<GrandClientDataCores>> grandClientDataCoresList ...
Therefore you need something like this:
for (Optional<GrandClientDataCores> gcdcOpt: grandClientDataCoresList) {
GrandClientDataCores gcdc = gcdcOpt.get();
....
values in grandClientDataCores are of type Optional<GrandClientDataCores>.
Your actual error is here:
protected List<GrandClientDataCores> getGrandClientDataCoreList(SubmitMode submitMode, String grandClientDataCore) throws Exception {
List<GrandClientDataCores> grandClientDataCoresList;
try {
grandClientDataCoresList = (List<GrandClientDataCores>) this.service.getGrandClientDataCoreList(submitMode, grandClientDataCore);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This cast is invalid
} catch ( Exception ex) {
throw new Exception(ex);
}
if (grandClientDataCore == null || grandClientDataCore.isEmpty()) {
throw new NoDataException("No CDC record to validate.");
}
return grandClientDataCoresList;
}
You will find that the actual type returned by this.service.getGrandClientDataCoreList is List<Optional<GrandClientDataCores>> so you must update your code accordingly, in a number of places. For starters...
protected List<Optional<GrandClientDataCores>> getGrandClientDataCoreList(SubmitMode submitMode, String grandClientDataCore) throws Exception {
List<Optional<GrandClientDataCores>> grandClientDataCoresList;
try {
grandClientDataCoresList = this.service.getGrandClientDataCoreList(submitMode, grandClientDataCore);
} catch ( Exception ex) {
throw new Exception(ex);
}
if (grandClientDataCore == null || grandClientDataCore.isEmpty()) {
throw new NoDataException("No CDC record to validate.");
}
return grandClientDataCoresList;
}
and everywhere that you invoke this method.

use the "get()" function of Optional, which will retrieve the object itself.
pay attention it will throw an exception if no object was populated into this Optional.

GrandClientDataCores values in List are wrapped with Optional, so you have to check if value present:
grandClientDataCores.isPresent()
and if it is then just get it:
grandClientDataCores.get();
Alternatively, you can do something like that:
grandClientDataCores.orElse(new GrandClientDataCores())
And I recommend to read this

Related

Is this a redundant NullPointerException catch?

Below Spring REST code returns List for a given ticketId.
Could a NullPointerException be thrown in this code ?
NullPointerException explicitly caught in TicketController:
catch (NullPointerException nullPointerException) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, nullPointerException.getMessage(), nullPointerException);
}
The thinking may have been when checking for null on the ticket id:
if (ticketId == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ticket id cannot be null");
}
the expectation is that a NullPointerException would be thrown but instead a ResponseStatusException is thrown ?
If the variable ticketId is a path parameter it can never be null as hit the base url / without a ticketId I receive:
There was an unexpected error (type=Method Not Allowed, status=405).
Entire source:
#RestController
public class TicketController {
private final TicketServiceImpl ticketServiceImpl;
public TicketController(TicketServiceImpl ticketServiceImpl) {
this.ticketServiceImpl = ticketServiceImpl;
}
#GetMapping(path = "/{ticketId}")
public ResponseEntity<List<TicketResponse>> getTicketsById(
#PathVariable("ticketId") final Long ticketId) {
try {
final List<TicketResponse> ticketsById = ticketServiceImpl.getAll(ticketId);
return new ResponseEntity<>(ticketsById, HttpStatus.OK);
}
catch (NullPointerException nullPointerException) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, nullPointerException.getMessage(), nullPointerException);
}
catch (TicketNotFoundException ticketNotFoundException) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Ticket id not found",
ticketNotFoundException);
}
}
}
#Service
public class TicketServiceImpl implements TicketService {
private final TicketRepository ticketRepository;
public TicketServiceImpl(TicketRepository ticketRepository) {
this.ticketRepository = ticketRepository;
}
#Override
public List<TicketResponse> getAll(Long ticketId) {
final List<TicketResponse> ticketResponselist = ticketRepository.findData(ticketId);
if (ticketId == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ticket id cannot be null");
}
else if (ticketResponselist.size() == 0) {
throw new TicketNotFoundException("ticket not found");
}
else {
return ticketResponselist;
}
}
}
#Repository
public interface TicketRepository {
public List<TicketResponse> findData(Long ticketId);
}
The if (ticketId == null) check should happen before the ticketRepository.findData(ticketId); is called.
Otherwise, the validation doesn't make sense.
Also, as a side note, catching NullPointerException is a bad practice. The reason is that having a null pointer exception thrown is mostly a sign of a coding smell. The code should be null-safe, by either using e.g. Optional or having a proper validation at the method level. In this case, it would be at the route level (which is the external input). From that point onward, if the validation is set, you're dealing with non nullable id.
This is also somehow related to returning null from a method, which is also a bad practice, since it requires a check in every method which then uses the returned value. This would pollute the code, will introduce a new level of abstraction, and will generally lead to nasty bugs.
NullPointerException check is not required in this case.
Side note : Its better to use the super type when passing as a method parameter until and unless you are pretty sure that no exception will be thrown instead of yours.

Bad return type in method reference: Cannot convert Employee to Optional<U>

I am trying to write a lambda function that gets employee location preference and have the code sample below.
But for my lambda function I get a compilation error at flatMap(this::buildEmployeeGeolocation)
saying Bad return type in method reference: cannot convert com.abc.EmployeeGeolocation to java.util.Optional<U>.
What am I missing here?
public Optional<EmployeeGeolocation> getEmployee(final SessionId sessionId) {
return Optional.ofNullable(employeePreferencesStore.getEmployeeAccountPreferences(sessionId))
.map(preferences -> preferences.getPreference(PreferenceKey.Location))
.filter(StringUtils::isNotBlank)
.map(this::readEmployeelocation)
.flatMap(this::buildEmployeeGeolocation);
}
private Optional<EncryptedGeolocation> readEmployeeLocation(#NonNull final String encryptedGeolocation) {
try {
return Optional.ofNullable(objectMapper.readValue(encryptedGeolocation, EmployeeGeolocation.class));
} catch (final IOException e) {
log.error("Error while reading the encrypted geolocation");
throw new RuntimeException(e);
}
}
private EmployeeGeolocation buildEmployeeGeolocation(#NonNull final EncryptedGeolocation unditheredEncryptedGeolocation) {
return EmployeeGeolocation.builder()
.latitude(10.0)
.longitude(10.0)
.accuracy(1.0)
.locationType(ADDRESS)
.build();
}
It seems like what you really need to do is swap the map and flatMap. Change the code
.map(this::readEmployeeLocation)
.flatMap(this::buildEmployeeGeolocation);
to
.flatMap(this::readEmployeeLocation) // since you already have an Optional<String>
.map(this::buildEmployeeGeolocation); // above results in Optional<EncryptedGeolocation>
Important: Inferred from the code Optional.ofNullable(...).map(...).filter(StringUtils::isNotBlank), that it would result in an Optional<String> until this operation.

Handling exceptions while returning values by Optional flatmap

I have tried implementing Optional from JAVA in the below code. getOrders() method throws a KException.
#Override
public Optional<List<Order>> getPendingOrders(AuthDTO authDTO) throws MyException {
List<Order> orders=null;
try {
Optional<KConnect> connection = connector.getConnection(authDTO);
if (connection.isPresent()) {
orders = connection.get().getOrders();
}
}catch (KException e){
throw new MyException(e.message,e.code);
}
return Optional.ofNullable(orders);
}
I tried to remove the isPresent() check and replace it with flatmap.
#Override
public Optional<List<Order>> getPendingOrders(AuthDTO authDTO) throws MyException {
return connector.getConnection(authDTO).map(p -> {
try {
return p.getOrders();
} catch (KException e) {
throw new MyException(e.message,e.code); // [EXP LINE]
}
});
}
In this case I am not able to catch KException and convert it to MyException. My code won't compile.
unreported exception com.myproject.exception.MyException; must be caught or declared to be thrown
1st snippet works perfectly fine for me. Is there a better way to do this? Please suggest.
Edit: This does not change if I make it map instead of flatmap.
The exact problem is that IntelliJ is saying unhandled exception: com.myproject.exception.MyException at [EXP LINE] even though the method has throws MyExpception present.

How to handle a PSQLException in java?

I have a unique constraint on one of my entities and whenever I get a PSQLException which occurs whenever that constraint is violated, I want to respond with a bad request.
This is my exception handler which I tried to implement:
#ControllerAdvice
public class DatabaseExceptionHandler {
#ExceptionHandler(value = PSQLException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleDatabaseExceptions(PSQLException e) {
// i want to respond with a bad request only when this condition is satisfied
//
// if (e.getSQLState().equals("23505")) {
//
// }
}
}
And this is where the model is saved in db:
public DepartmentForHoliday setDepartment(DepartmentForHoliday department) {
if (department.getDepartmentId() == null) {
Department savedDepartment = new Department();
savedDepartment.setName(department.getName());
try {
departmentRepository.save(savedDepartment);
} catch (PSQLException e) {
/*here i have a compiler error which says that this exception is never thrown in the corresponding try block, but where ?*/
}
}
This is the exception that is thrown when I add a duplicate entry:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_1t68827l97cwyxo9r1u6t4p7d"
Detail: Key (name)=(Tech) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458) ~[postgresql-9.4.1211.jre7.jar:9.4.1211.jre7]
How to handle PSQLExceptions ? Should I make my own exception as a wrapper or how to solve this problem ?
Key problem is that PSQLException is wrapped into some Spring exception (which I assume from your code); you have to unwrap it (for example using guava's Throwables):
public DepartmentForHoliday setDepartment(DepartmentForHoliday department) {
if (department.getDepartmentId() == null) {
Department savedDepartment = new Department();
savedDepartment.setName(department.getName());
try {
departmentRepository.save(savedDepartment);
} catch (RuntimeException e) {
Throwable rootCause = com.google.common.base.Throwables.getRootCause(e);
if (rootCause instanceof SQLException) {
if ("23505".equals(((SQLException) rootCause).getSQLState())) {
// do smth interesting :)
}
}
}
}
}
Once you do that you can throw your custom exception and handle it in DatabaseExceptionHandler
You are catching PSQLException. Instead of that, please catch SQLException. With SQLException you will can handle all this SQL exceptions.
You can check the SQLException knowledge at this link
Then in your code just treat the SQLException as you want. The most generic catch clause is the following one:
catch (SQLException e)
{
System.out.println("ERROR: Fetch statement failed: " +
e.getMessage());
}
With this code you are printing the exception. If you want more information, check this
This is quite late, but building on previous responses I was able to solve it as so:
try {
return this.projectRepository.saveAndFlush(patchedProjectEntity);
} catch (DataIntegrityViolationException e) {
if (e.getMostSpecificCause().getClass().getName().equals("org.postgresql.util.PSQLException") && ((SQLException) e.getMostSpecificCause()).getSQLState().equals("23505"))
throw new UniqueConstraintViolationException("", e.getMostSpecificCause());
throw e;
}
Where UniqueConstraintViolationException is a custom exception and handled with a spring controller advice.
You might as well register an exception handler for that wrapped exception (that #radek mentioned) directly.
In your case that's:
#ExceptionHandler(DataIntegrityViolationException::class)
protected fun handleDataIntegrityException(ex: DataIntegrityViolationException, request: WebRequest) : ResponseEntity<SomeBody>{
return ResponseEntity.badRequest().body(someBodyHere)
}
The error is converted within convertHibernateAccessException in org.springframework.orm.jpa.vendorHibernateJpaDialect, which has already processed away from PSQL. You can add a breakpoint there and follow the stacktrace.
There is a lot of proxy'ing happening under the hood, but the takeaway is that there is always a readable, expressive Exception to use directly.

throw simple exception with message

There is simple way to throw exception with message in java ?
In the following method I check for types and if the type doesn't exist i want to throw message
that the type is not supported ,what is the simplest way to do that ?
public static SwitchType<?> switchInput(final String typeName) {
if (typeName.equals("java.lang.String")) {
}
else if (typeName.equals("Binary")) {
}
else if (typeName.equals("Decimal")) {
}
return null;
}
Use the Exception Constructor which takes a String as parameter:
if (typeName.equals("java.lang.String")) {
}
else if (typeName.equals("Binary")) {
}
else if (typeName.equals("Decimal")) {
}
else {
throw new IllegalArgumentException("Wrong type passed");
}
The standard way to handle an illegal argument is to throw an IllegalArgumentException:
} else {
throw new IllegalArgumentException("This type is not supported: " + typeName);
}
And try not to return null if you can avoid it.
this method cannot throw an exception really
because typeName in input parameter of function is a String already..

Categories

Resources