I have a number of typed exceptions which all share the same characteristic: they hold a status (int) field which is always non-zero. The code typically checks for a status variable and if that is non-zero throws the corresponding exception (depending on the context). I.e.:
if (status != 0) throw new AStatusException(status);
... // other context
if (status != 0) throw new BStatusException(status);
... // other context
if (status != 0) throw new CStatusException(status);
Mostly out of curiusity I thought I might implement this common functionality in a static method throwIfNotZero of a base class StatusException and have the various A, B, CStatusException classes all inherit that class. This would hopefully allow me to write code like this:
AStatusException.throwIfNonZero(status);
... // other context
BStatusException.throwIfNonZero(status);
... // other context
CStatusException.throwIfNonZero(status);
Sadly, the closest I got is the code I append at the end of the post, which is not very satisfactory. Is there a better way to do it, perhaps without using Reflection and / or avoiding the requirement to pass the class instance which appears redundant (see 'usage')?
Base Exception
import java.lang.reflect.InvocationTargetException;
public class StatusException extends Exception {
public int status;
public StatusException (int status) {
this.status = status;
}
public static <T extends StatusException> void raiseIfNotZero(Class<T> klass, int code) throws T{
try {
if (code != 0) throw klass.getConstructor(Integer.TYPE).newInstance(code);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
usage:
AStatusException.raiseIfNotZero(AStatusException.class, status);
BStatusException.raiseIfNotZero(BStatusException.class, status);
You can overload function raiseIfNotZero() in the super class StatusException.
And call it like this
StatusException.raiseIfNotZero(AStatusException.class, status);
StatusException.raiseIfNotZero(BStatusException.class, status);
public static int final STATUS_EXCEPTION_A=1;
public static int final STATUS_EXCEPTION_A=2;
raiseIfNotZero(int type, int status)
{
switch(type)
{ case STATUS_EXCEPTION_A: throw new AStatusException(); break;
case STATUS_EXCEPTION_B: throw new BStatusException(); break;
...
}
}
Related
I have a Spring Boot project in which I am adding the below Test of some of the classes.
#Test
void documentException() {
assertThrows(DocumentException.class, () -> {
try {
throw new DocumentException();
} catch (Exception ex) {
assertEquals("Error converting document format", ex.getMessage());
assertEquals(417 /* EXPECTATION_FAILED */, ex.getHttpStatus());
assertEquals(ErrorCodes.DOCUMENT_ERROR, ex.getCode());
throw ex;
}
});
}
#Test
void maxUserException() {
assertThrows(MaxUserException.class, () -> {
try {
Integer maxUsers = 5;
throw new MaxUserException(maxUsers);
} catch (Exception ex) {
Integer maxUsers = 5;
assertEquals("Excedido el número máximo de "+ maxUsers +" dispositivos", ex.getMessage());
assertEquals(403 /* FORBIDDEN */, ex.getHttpStatus());
assertEquals(ErrorCodes.MAX_USERS_DEVICES, ex.getCode());
throw ex;
}
});
}
#Test
void docFormatException() {
assertThrows(DocFormatException.class, () -> {
try {
throw new DocFormatException();
} catch (Exception ex) {
assertEquals("Document format", ex.getMessage());
assertEquals(415 /* UNSUPPORTED_MEDIA_TYPE */, ex.getHttpStatus());
assertEquals(ErrorCodes.DOCUMENT_ERROR, ex.getCode());
throw ex;
}
});
}
For each class I use the same method.
Would there be any way to create a class with a #Test and call it for each class? So as not to have to create such a large structure for each of the classes.
What I want is to make a general method and apply it to each of the classes. So as not to have to repeat the same structure for all classes.
Well, answering directly to your question and using your actual examples - if you want to avoid code duplication then you can use some utility method.
Assuming your exceptions are subtypes of your custom class or implement the same interface which have methods getHttpStatus and getCode. Let's say parent class or interface has name CustomException.
Create a new class, for example TestUtils and define the method which can be reused is your tests, something like that (idk what type getCode() should return, so I assume it's String)
public class TestUtils {
public static void testException(CustomException exception, String message,
String errorCode, int httpStatus) {
assertThrows(exception.getClass(), () -> {
try {
throw exception;
} catch (CustomException ex) {
assertEquals(message, ex.getMessage());
assertEquals(httpStatus, ex.getHttpStatus());
assertEquals(errorCode, ex.getCode());
throw ex;
}
});
}
}
Then your test methods can be simplified:
#Test
void documentException() {
TestUtils.testException(new DocumentException(),
"Error converting document format",
417,
ErrorCodes.DOCUMENT_ERROR);
}
maxUserException() a bit trickier but still works:
#Test
void maxUserException() {
int maxUsers = 5;
MaxUserException exception = new MaxUserException(maxUsers);
String message = "Excedido el número máximo de "+ maxUsers +" dispositivos";
TestUtils.testException(exception, message, ErrorCodes.MAX_USERS_DEVICES, 403);
}
Hope it can be helpful. However it's worth mentioning - if it's your real test code and it's written exactly like this, then those methods attempt to test that your custom exceptions are created with correct default parameters (that's all) and in that case, test methods can be simplified as they are overcomplicated right now.
Your example test methods seems bit complicated, but it worth mentioning there in JUnit5 there are annotations to handle parameterized test.
You should look into these documents:
Java doc for #ParameterizedTest , #ValueSource , #CsvSource.
here is a sample example of how to parameterized a test:
#ParameterizedTest
#CsvSource(value = {
// input and expected output separated by :
"test:test",
"tEst:test",
"Java:java"
}, delimiter = ':')
void toLowerCase_ShouldGenerateTheExpectedLowercaseValue(String input, String expected) {
String actualValue = input.toLowerCase();
assertEquals(expected, actualValue);
}
Have a look in this Guide to JUnit 5 Parameterized Tests.
I got an issue to handle NoSuchElementException and NullPointerEception.
I tried to handle NoSuchElementException error from this code:
public Item shop(ItemShopParam itemShopParam) {
String orderNumber = itemShopParam.getOrderNumber();
Shipment shipment = shipmentService.findByNumber(orderNumber);
Item item = findBySku(shipment.getId(), itemShopParam.getItemSku());
Job job = item.getShipment().getJobs().stream().filter(j -> j.getType().equals(Job.Type.RANGER)).findFirst().get();
checkJobState(job);
private void checkJobState(Job job) {
if (job.getState() == Job.State.INITIAL)
throw new JobNotStartedException();
if (job.getState() == Job.State.FINISHED)
throw new JobAlreadyFinishedException();
}
by replace get() with Optional().orElse(null). But, it returned another error exception NullPointerException. I know why this happened because checkJobState check null value of job.
The enum state:
public enum State {
INITIAL(0),
STARTED(1),
LAST_ITEM_PICKED(2),
FINALIZING(3),
ACCEPTED(4),
DELIVERING(5),
FOUND_ADDRESS(6),
FINISHED(7),
FAILED(8);
What is the best practice to avoid NoSuchElementException without return NullPointerException?
You can use Optional.isPresent() check:
Optional<Job> maybeJob = item.getShipment().getJobs().stream().filter(j -> j.getType().equals(Job.Type.RANGER)).findFirst();
if(maybeJob.isPresent()) {
checkJobState(job);
}
or even better an ifPresent():
Optional<Job> maybeJob = item.getShipment().getJobs().stream().filter(j -> j.getType().equals(Job.Type.RANGER)).findFirst().ifPresent(job -> checkJobState(job));
you can put the instructions to get the job from itemShopParam in a java Function, in this way you can easy test it.
Then use try catch to get any unexpected behaviour and specialise it in your exception inside a catch block.
The exception fired could be checked, if extends Throwable or Runtime if you wants manage it optionally.
//FUNCTION CLASS
class FromItemShopParamToJob implements Function<ItemShopParam,Item>
{
#Override
public Item apply(ItemShopParam itemShopParam) {
Item i=new Item();
//instructions to get job
return i;
}
}
class FromItemToJob implements Function<Item,Job> {
#Override
public Job apply(Item item) {
Job j=new Job();
//instructions to get job
return j;
}
}
//YOUR EXCEPTION CLASS
public class JobNotFoundException extends RuntimeException{
public JobNotFoundException(String message) {
super(message);
}
}
//YOUR METHOD
public void getJobFromItemShop(ItemShopParam param){
try {
Item item = new FromItemShopParamToJob().apply(param);
Job j=new FromItemToJob().apply(item);
} catch (Exception e){
System.out.print(e);
throw new JobNotFoundException(e.toString());
}
}
I have a class called Packet and a class called PacketClientConnecting witch extends it. The instances of PacketClientConnecting and other packets are stored in ArrayList<Packet>.
I want to have access to id value in static and non-static ways eg PacketClientConnecting.getStaticId() or packetArrayList.get(5).getId().
How can i do this without overriding two functions in every class?
I don't think there's a really smooth way of doing this, but one can achieve what you want by using reflection (only once: in the base class):
class Packet {
public static int getStaticId() {
return 1;
}
// This method is virtual and will be inherited without change
public int getId() {
try {
// Find and invoke the static method corresponding
// to the run-time instance
Method getStaticId = this.getClass().getMethod("getStaticId");
return (Integer) getStaticId.invoke(null);
// Catch three reflection-related exceptions at once, if you are on Java 7+,
// use multi-catch or just ReflectiveOperationException
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
Now in the subclass all you need is define getStaticId():
class PacketClientConnecting extends Packet {
public static int getStaticId() {
return 2;
}
}
Let's test it:
class Main {
public static void main(String[] args) {
// Both print 1
System.out.println(Packet.getStaticId());
System.out.println(new Packet().getId());
// Both print 2
System.out.println(PacketClientConnecting.getStaticId());
System.out.println(new PacketClientConnecting().getId());
}
}
If you want to avoid the overhead of calling reflective operations every time you call getId(), you can use a field in the base class to cache the id:
class Packet {
public static int getStaticId() {
return 1;
}
private final int id = computeId();
public int getId() {
return id;
}
// This method runs once per instance created
private int computeId() {
try {
Method getStaticId = this.getClass().getMethod("getStaticId");
return (Integer) getStaticId.invoke(null);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
I have a tree of projectile classes I am trying to use some reflection to not implement every combination possible by hand when most of it would be copy paste or at best a lot of one liner virtual methods to override attributes.
Basically I have different weapon types that shoot in different patterns such as twin linked, alternating or just a single weapon, and a number of different projectiles such as missiles, bullets, sniper bullets.
The syntax is currently the flavor of:
public Bomber() {
weapons.add(new TwinLinkedWeapon<Missile>(Missile.class));
weapons.add(new Weapon<Bullet>(Bullet.class));
}
and Weapon looks like:
public class Weapon<T extends Projectile> {
long lastShot;
protected Constructor<? extends T> ctor;
public Weapon(Class<? extends T> projectileType) {
try {
ctor = projectileType.getDeclaredConstructor(actor.Actor.class);
} catch (SecurityException e) {
e.printStackTrace();
return;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return;
}
lastShot = 0;
}
protected long getLastShotTime() {
return lastShot;
}
protected T newProjectile(actor.Actor ship){
T projectile = null;
try {
projectile = ctor.newInstance(ship);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return projectile;
}
protected void setLastShotTime(long time) {
lastShot = time;
}
public void shoot(Actor ship) {
//calculates time passed in milliseconds
if((System.currentTimeMillis() - getLastShotTime()) > T.getShotCoolDown()) {
game.Game.getActors().add(newProjectile(ship));
setLastShotTime(System.currentTimeMillis());
}
}
public String getWeaponName(){
return "" + getClass().getName() + " " + ctor.getName();
}
}
My issue is fairly simple to understand. On the line if((System.currentTimeMillis() - getLastShotTime()) > T.getShotCoolDown())
T is an abstract Projectile class instead of a derived class such as Bullet or Missile so when I call the static method T.getShotDelay() it always calls Projectile.getShotDelay() instead of the derived class.
My only solution is to make an instance of T with ctor and have that attribute be instance based instead of class based, but that seems like a 'less than ideal' solution.
I am new to java reflection and am unsure of the syntax to achieve this. I would appreciate any input.
You can get static methods from Class objects and invoke them on null, no need to call constructors. Just take the runtime class of T, that is:
T t = something;
Class<?> tClass = t.getClass();
Method staticMethod = tClass.getMethod("methodName");
staticMethod.invoke(null); // Static methods can be invoked on null.
You should use instance methods to get the functionality that you want.
Maybe you should consider using abstract factory pattern.
You can have IProjectileFactory interface that is implemented by MissileFactory and BulletFactory.
The factories are able to create new projectiles Missile and Bullet that implement the IProjectile interface. The projectile factories are given as parameters when you create new weapon instances (i.e. new TwinLinkedWeapon(new MissileFactory())).
This is the original exception code
public class NoValueForParametarException extends Exception {
private Exception nestedException;
private int errorCode;
public NoValueForParametarException(String message) {
super(message);
}
public NoValueForParametarException(Exception ex,String message) {
super(message);
this.nestedException = ex;
}
public NoValueForParametarException(String message, int errorCode) {
super(message);
this.setErrorCode(errorCode);
}
public Exception getNestedException() {
return this.nestedException;
}
public void setNestedException(Exception nestedException) {
this.nestedException = nestedException;
}
public int getErrorCode() {
return this.errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String toString() {
StringBuffer errorMsg = new StringBuffer();
errorMsg.append("[" + super.getMessage() + "]:");
errorMsg.append((this.nestedException != null) ? ("\n[Nested exception]:" + this.nestedException):"");
return errorMsg.toString();
}
}
and this is the new one
public class NoValueForParametarWebServiceException extends NoValueForParametarException {
public NoValueForParametarWebServiceException(String message) {
super(message);
}
public NoValueForParametarWebServiceException(Exception ex,String message) {
super(message);
this.setNestedException(ex);
}
public NoValueForParametarWebServiceException(String message, int errorCode) {
super(message);
this.setErrorCode(errorCode);
}
public String toString() {
StringBuffer errorMsg = new StringBuffer();
errorMsg.append(super.getMessage());
errorMsg.append((this.getNestedException() != null) ? ("\n[Nested exception]:" + this.getNestedException()):"");
return errorMsg.toString();
}
}
All I need is to change the part of the toString() method so instead of errorMsg.append("[" + super.getMessage() + "]:"); I have errorMsg.append(super.getMessage());. The problem appears when, in a method, the original is thrown because the catch block set to NoValueForParametarWebServiceException doesn't catch the original. I know I could catch the original and just re-throw the new one (which would also be satisfying), but I was wondering if there is another way.
EDIT: It seems what I need is unclear, so to be more clear:
The program throws NoValueForParametarException. I want to catch it but use the toString() method of NoValueForParametarWebServiceException (that is the sole reason of creating the new class) because I need the output format of the new version without changing the old.
I don't see any reason to subclass your first exception. Also, if you get rid of the nestedException instance variable and use java.lang.Throwable's cause instead, you don't have to mess with overriding toString and you can delete most of this code.
The problem appears when, in a method,
the original is thrown because the
catch block set to
'NoValueForParametarWebServiceException'
doesn't catch the original. I know I
could catch the original and just
re-throw the new one (which would also
be satisfying)
You don't need to re throw child exception.
Just catch parent exception in this case.
try{
//your code
}catch(NoValueForParametarException e){
//whatever handling you need to do. suppose you call toString() method
System.out.println(e.toString());
}
In above case catch block will be executed if any of your exceptions are thrown
(NoValueForParametarException or NoValueForParametarWebServiceException).
And depending upon which exception is thrown its toString() method will be called. (Simple inheritance rule) i.e.
NoValueForParametarException is
thrown toString defined in
NoValueForParametarException class
will be called for instance.
And if
NoValueForParametarWebServiceException
is thrown then overriden toString
method from
NoValueForParametarWebServiceException
will be called.
Some tutorials related to exceptions:
http://download.oracle.com/javase/tutorial/essential/exceptions/index.html
http://tutorials.jenkov.com/java-exception-handling/index.html
Hope this helps.