My problem is very usual but i can't seem to find any solution. I have searched a lot but didn't find anything
Situation:
tried to insert a row which caused foreign key violation that caused my transaction to rollback.
No matter what exception i handle it always throws 500 from my rest endpoint which is not acceptable at all
Question:
How to handle this gracefully. Below is my code which is not working
#Transactional(dontRollbackOn={InvalidModelException.class,PersistenceException.class,ConstraintViolationException.class,MySQLIntegrityConstraintViolationException.class})
#Override
public PointAudit createPointAudit(PointAudit pointAudit) throws EmptyModelException, InvalidModelException {
if(pointAudit != null) {
try {
this.entityManager.persist(pointAudit);
this.entityManager.flush();
}
catch(RollbackException x) {
LOGGER.error(x.getMessage(), x);
}
catch(PersistenceException x) {
if(x.getCause() instanceof ConstraintViolationException) {
if(x.getCause().getCause() instanceof MySQLIntegrityConstraintViolationException)
{
MySQLIntegrityConstraintViolationException e = (MySQLIntegrityConstraintViolationException)x.getCause().getCause();
if(e.getMessage().contains("USER_ID")) {
throw new InvalidModelException("Invalid user is provided");
}
else {
if(e.getMessage().contains("STATUS")) {
throw new InvalidModelException("Invalid status is provided");
}
else {
if(e.getMessage().contains("CHANNEL")) {
throw new InvalidModelException("Invalid channel is provided");
}
else {
if(e.getMessage().contains("ACTION")) {
throw new InvalidModelException("Invalid action is provided");
}
}
}
}
}
}
else {
while( !(x.getCause() instanceof RollbackException) || x.getCause() == null) {
LOGGER.error(x.getMessage(), x);
}
}
}
}
else {
throw new EmptyModelException("Point Audit is empty");
}
return pointAudit;
}
If any further code is required please let me know
Related
Is there a way to eliminate all the "if" statements from this class and still maintain the exact same functionality ?
So far I managed to simplify the code by creating the 2 extra functions: isNameValid and isPhoneValid, but I need a way to get rid of all the "if" statements.
public class ClientValidator implements Validator<Client> {
#Override
public void validate(Client entity) throws ValidatorException {
if(!isNameValid(entity.getName())){
throw new ClientException("Invalid name!");
}
if(!isPhoneValid(entity.getPhone())){
throw new ClientException("Invalid phone number!");
}
}
private boolean isNameValid(String name) {
return name.length() > 1 && name.length() < 100;
}
private boolean isPhoneValid(String phone) {
try {
Long.parseLong(phone);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}
you can try optionals and do filtering on the methods, but you miss reason specific exceptions:
Optional
.of(entity)
.filter(entity -> isNameValid(entity.getName())
.filter(entity -> isPhoneValid(entity.getPhone())
.orElseThrow(() -> new ClientException("Wrong client data"));
Is there a way to eliminate all the "if" statements from this class and still maintain the exact same functionality ?
Yes. It's a hack, but if isn't the only flow-control. Easiest I see, a while loop with the same logic. Like,
#Override
public void validate(Client entity) throws ValidatorException {
while (!isNameValid(entity.getName())) {
throw new ClientException("Invalid name!");
}
while (!isPhoneValid(entity.getPhone())) {
throw new ClientException("Invalid phone number!");
}
}
You could also use switch statements like
#Override
public void validate(Client entity) throws ValidatorException {
switch (isNameValid(entity.getName())) {
case false:
throw new ClientException("Invalid name!");
}
switch (isPhoneValid(entity.getPhone())) {
case false:
throw new ClientException("Invalid phone number!");
}
}
What about this :
#Override
public void validate(String entity) throws ClientException {
String message = !isNameValid(entity.getName()) ? "Invalid name!"
: !isPhoneValid(entity.getPhone()) ? "Invalid phone number!" : "";
Stream.of(message).filter(m -> m.isEmpty()).findAny()
.orElseThrow(() -> new ClientException (message));
}
I could think of some dirty tricks like
public void validate(Client entity) throws ValidatorException {
try {
int len = entity.getName().length();
int isshort = 1 / len;
int islong = 1 / max (0, 100- length);
} catch (Exception e) {
throw new ClientException("Invalid name!");
}
try {
Long.parseLong(entity.getPhone());
} catch (NumberFormatException e) {
throw new ClientException("Invalid phone number!");
}
}
So no if needed
I have a method which tries to get the current message in an arraylist of mesages and if there are none then it returns null, however I get an index out of bounds exception and I can't understand why
public Message getCurrent() {
if(this.size() <= 0) {
return null;
}else {
return this.get(currentMessageIndex);
}
}
The following calls the above method in another class and throws the exception:
public void run() {
while (running) {
//Message msg = clientQueue.getLast(); // Matches EEEEE in ServerReceiver
Message msg = clientQueue.getCurrent();
System.out.flush();
if (msg != null) {
if (msg.getSent() == false) {
client.println(msg);// Matches FFFFF in ClientReceiver
client.flush();
msg.setSent();
}
}
}
return;
}
public Message getCurrent() {
if(this.size() <= 0) {
return null;
}else {
return (this.size() > currentMessageIndex) ? this.get(currentMessageIndex) : null;
}}
Can you try with this, I have handled fail over case.
Just use
this.size()-1
Instead of
this.size()
I need to see the result as a boolean result: true. But there's a catch I need to do it in a non-ordinary way.
import java.io.IOException;
public class FlashLight {
private Bulb bulb;
private Battery[] batteries;
public void on() {
try {
if (this.IsThereEnoughPower()) {
this.bulb.setOn(true);
for (Battery b : batteries) {
b.setPower(b.getPower() - this.bulb.getBrightness());
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
this.setBatteries(new Battery[4]);
}
}
I need to catch the exception in method on() but i can only modify method: DetermineIfFlashlightCanBeTurnedOn
public boolean DetermineIfFlashlightCanBeTurnedOn() throws IOException {
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
}
private boolean DetermineIfBatteriesAreInstalled() throws IOException {
if (batteries.length < 4) {
throw new IOException(Math.abs(-4 + batteries.length));
}
for (Battery b : batteries) {
if (b == null) {
return false;
}
}
return true;
}
private boolean IsThereEnoughPower() {
for (Battery b : batteries) {
if (b.getPower() < MIN_BATTERY_POWER) {
return false;
}
}
return true;
}
private static void testLatarki(String... args) {
FlashLight flashlight = new Flashlight();
System.out.println(flashlight.DetermineIfFlashlightCanBeTurnedOn());
}
}
Exception can be caught only in on() method.
DetermineIfBatteriesAreInstalled() DetermineIfFlashlightCanBeTurnedOn
must be signed as: throws IOException.
You can use try{}catch(){} instead :
public boolean DetermineIfFlashlightCanBeTurnedOn() {
try {
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
} catch (Exception e) {
//log your exception
}
return false;
}
I forgot to tell you guys i can use try/catch blocks only in on()
method
In this case you can use RuntimeException you don't need to use throws IOException in your method:
if (batteries.length < 4) {
throw new RuntimeException(Math.abs(-4 + batteries.length)+"");
}
So :
public boolean DetermineIfFlashlightCanBeTurnedOn() {
//--not need to use throw throws IOException-------^
return bulb != null && DetermineIfBatteriesAreInstalled() && IsThereEnoughPower();
}
private boolean DetermineIfBatteriesAreInstalled() {
//--not need to use throw throws IOException------^
if (batteries.length < 4) {
throw new RuntimeException(Math.abs(-4 + batteries.length) + "");
//----------^^
}
for (Battery b : batteries) {
if (b == null) {
return false;
}
}
return true;
}
You can read more here Is there a way to throw an exception without adding the throws declaration?
I have a very curious situation.
I'm trying to execute EJB's method and returns the result with JAX-RS
public Service readSingle(...) {
try {
service.query(...);
} catch (final NoResultException nre) {
throw new NotFoundException(...);
} catch (final NonUniqueResultException nure) {
throw new BadRequstException(...);
}
}
The query method requires some values and a BiFuction and a Function.
The actual call looks like this.
try {
return serviceService.<Service>query(
id,
ofNullable(matrixParameters.getFirst("onid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("tsid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("sid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("number"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("programId"))
.orElse(null),
operatorId,
(builder, root) -> emptyList(),
TypedQuery::getSingleResult);
} catch (final NoResultException nre) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} catch (final NonUniqueResultException nure) {
throw new BadRequestException("multiple entities identified");
}
Ok I passed TypedQuery::getSingleResult and I expect NonUniqueResultException should be caught when it has to be thrown.
But Payara keep responding with 500 and the log shows that the NonUniqueResultException has never caught by the code.
I disabled my ExceptionMappers the the results are same.
Ok. I figured it out. I had to do this.
try {
// execute EJB
} catch (final EJBTransactionRolledbackException ejbtre) {
Exception leaf = ejbtre;
try {
for (Exception c;
(c = ((EJBException) leaf).getCausedByException()) != null;
leaf = c);
} catch (final ClassCastException cce) {
}
logger.severe("causedByException: " + leaf);
if (leaf instanceof NoResultException) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} else if (leaf instanceof NonUniqueResultException) {
throw new BadRequestException(
"multiple entities identified by "
+ serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
}
throw new InternalServerErrorException(ejbtre);
}
This is far nasty beyond I've expected. The EJB's method design is not good.
Is there any way to do this more simply?
Let me introduce one of my utility class I used to justify myself.
public final class EJBExceptions {
private static final Logger logger
= getLogger(EJBExceptions.class.getName());
public static Stream<Exception> causedByExceptions(EJBException ejbe) {
final Stream.Builder<Exception> builder = Stream.builder();
while (ejbe != null) {
final Exception causedByException = ejbe.getCausedByException();
if (causedByException != null) {
builder.add(causedByException);
} else {
break;
}
if (causedByException instanceof EJBException) {
ejbe = (EJBException) causedByException;
} else {
break;
}
}
return builder.build();
}
public static Optional<Exception> lastCausedByException(
final EJBException ejbe) {
return causedByExceptions(ejbe).reduce((first, second) -> second);
}
private EJBExceptions() {
super();
}
}
I have a java app that try to insert a row into the table and com.ibatis.common.jdbc.exception.NestedSQLException is thrown with the Cause com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException
When I try to insert dublicate data for a unique-key constraint.
How do I catch that exception?
To get to the root cause you can do something like this:
try {
//insert
} catch (NestedSQLException e) {
Throwable t = e;
while(t.getCause() != null) {
t = t.getCause();
}
//in your situation, now t should be MySQLIntegrityConstraintViolationException
if (t instanceOf MySQLIntegrityConstraintViolationException) {
//do something
}
}
In case it helps someone. #tibtof's is correct and got me to:
public int insert(MyObject myObject) {
int recCount = -1;
try {
recCount = insert(myObject, MyObjectMapper.class);
} catch (Throwable e) {
Throwable t = e;
while (t.getCause() != null) {
t = t.getCause();
if (t instanceof SQLIntegrityConstraintViolationException) {
// get out gracefully.
recCount = -1;
return recCount;
}
}
//Something else wicked wrong happened.
LogUtils.error(log, e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
return webGroup.getWebGroupId().intValue();
}