Is there any way to convert below function into one function in Java ? I tried cascading it using (TestRow ) but that doesn't work.
public void testWindow (TestRow window, String title) {
if (window != null) {
try {
window.zClose(window);
} catch (HarnessException e) {
e.printStackTrace();
}
window = null;
}
}
public void testWindow (TestColumn window, String title) {
if (window != null) {
try {
window.zClose(window);
} catch (HarnessException e) {
e.printStackTrace();
}
window = null;
}
}
Here TestRow and TestColumn is custom types.
Calling would be same way but due to custom window names, i need to copy paste same function many times which i think can be avoidable.
Extract your common logic in a separate method with common windows class as a parameter and call this common method in many places. E.g.
public void testWindow (TestRow window, String title) {
closeWindow(window);
}
public void testWindow (TestColumn window, String title) {
closeWindow(window);
}
private void closeWindow(CommonWindowsClass window) {
if (window != null) {
try {
window.zClose(window);
} catch (HarnessException e) {
e.printStackTrace();
}
window = null;
}
}
Here CommonWindowsClass is superclass both for TestRow and TestColumn classes.
UPDATE also I suppose you actually don't need this code line window = null; at all
You can use inheritance. Something like:
public abstract class Test {
public abstract void zClose( Teste t );
}
public class TestRow extends Test {
#Override
public void zClose( Test t ) {
// code...
}
}
public class TestColumn extends Test {
#Override
public void zClose( Test t ) {
// code...
}
}
public void testWindow (Test window, String title) {
if (window != null) {
try {
window.zClose(window);
} catch (HarnessException e) {
e.printStackTrace();
}
window = null;
}
}
Related
The project has the test Test_FindYNetNewsViaGoogle.java
public class Test_FindYNetNewsViaGoogle extends TestBase {
#Test
public void testGoToYNNHomeUrl(){
app.google().goToGoogleHome();
app.google().search("class_name");
app.google().enterSite(webElement2);
assertThat(app.browser().whatSiteIsOpened(), equalTo("urlYNetNews"));
}
}
A test scenario includes performance of app.google().search("www.ynetnews.com") that is located in GoogleHelper.class
public class GoogleHelper extends HelperBase{
private final String googleHomeUrl = "https://www.google.com/";
public GoogleHelper(WebDriver wd) {super(wd);}
public void goToGoogleHome() {
String curUrl = wd.getCurrentUrl();
if (googleHomeUrl.equals(curUrl)) {return;}
wd.navigate().to(googleHomeUrl);
}
#StaleElementAnnotation(retries = 2, seconds = 1)
public void search(String search) {
WebElement we_search = wd.findElemnt(By.className(search));
click(we_search);
}
public void click(WebElement search) {
// was refresh page
throw new StaleElementReferenceException("test exception");
}
public void enterSite(WebElement url){
click(url.locator));
}
}
I special write throw the StaleElementReferenceException exception, in order to image that after the previous step there were refresh of page.
So, to resolve this I need to change search(String) to
public void search(String search) {
int count = 0;
while (count < DEFAULT_RETRIES) {
try {
++count;
return searchService(search);
} catch (StaleElementReferenceException e) {
Thread.sleep(1000);
}
}
return null;
}
private void searchService(String search) {
WebElement we_search = wd.findElemnt(By.className(search));
click(we_search);
}
This okay if you have few those methods. But if there are many of it. So I think that there is solve in which we can invoke some Listener that can call in this case our initial method by surrounded it with as above written.
I have not found any TestNg listeners can give only test method name where was throw the exception. In my case it is Test_FindYNetNewsViaGoogle.testGoToYNNHomeUrl() and not GoogleHelper.click(WebElement search).
Please assist me!
First, you need to have a static method to retry the required methods. Maybe you can add this to your GoogleHelper class.
public static void retry(Runnable method, int maxTries, long seconds) throws InterruptedException {
int count = 0;
while (count < maxTries) {
try {
++count;
method.run();
} catch (RuntimeException e) {
TimeUnit.SECONDS.sleep(seconds);
}
}
}
Now you could use the above method in your test.
public class Test_FindYNetNewsViaGoogle extends TestBase {
#Test
public void testGoToYNNHomeUrl(){
app.google().goToGoogleHome();
GoogleHelper.retry(() -> app.google().search("class_name"), 2 , 1);
app.google().enterSite(webElement2);
assertThat(app.browser().whatSiteIsOpened(), equalTo("urlYNetNews"));
}
}
I'm building a GUI application in Java using an application framework (Netbeans Platform) which requires a large amount of nearly identical classes to implement extremely similar Action classes. I've spent a lot of time attempting to generate these actions programmatically. Although I'm able to generate the Actions, the framework utilizes annotations during compile time to generate other internal cache/data files which I've been unable to reproduce using a programmatic approach.
I'm wondering if code generation tools are a better solution, or perhaps some custom annotations which wrap the framework annotations. Perhaps something like Lombok, or maybe a maven plugin. But don't know where to start and am not sure if this is even a good path to explore. Ideally, I think it would be great to define the actions in a data file and generate the java code at compile time.
The project is open source, and a number of other actions are on github. Here is an example of what the template might look like, the pieces I would need to inject replaced with {{string}}, {{code}} and {{int}}:
// imports omitted
#ActionID(
category = {{string}},
id = {{string}})
#ActionRegistration(
iconBase = {{string}},
displayName = "resources.MessagesBundle#" + {{string}},
lazy = false)
#ActionReferences({
#ActionReference(
path = {{string}},
position = {{int}})
})
public final class {{string}} extends AbstractAction implements UGSEventListener {
public static final String ICON_BASE = {{string}};
private BackendAPI backend;
public SoftResetAction() {
this.backend = CentralLookup.getDefault().lookup(BackendAPI.class);
this.backend.addUGSEventListener(this);
putValue("iconBase", ICON_BASE);
putValue(SMALL_ICON, ImageUtilities.loadImageIcon(ICON_BASE, false));
putValue("menuText", {{string}});
putValue(NAME, {{string}});
}
#Override
public void UGSEvent(UGSEvent cse) {
java.awt.EventQueue.invokeLater(() -> setEnabled(isEnabled()));
}
#Override
public boolean isEnabled() {
{{code}}
}
#Override
public void actionPerformed(ActionEvent e) {
{{code}}
}
}
You should try a code generator like Telosys ( http://www.telosys.org/ )
This tool is designed for this kind of situation, you just have to create a template for each type of repetitive class and launch the generation.
For more information see the templating principles : http://www.telosys.org/templates.html
Everything is free and open source, so you can reuse existing templates and adapt them according to your needs.
Some interresting posts about this tool :
https://modeling-languages.com/telosys-tools-the-concept-of-lightweight-model-for-code-generation/
https://dzone.com/articles/telosys-a-code-generation-tool-by-laurent-guerin
You can design a public Action class for common using just like blow. This is only a section of sample code. If some modules has its own biz logical, you can implements this PubAction to any subclass.
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.AbstractAction;
public abstract class PubAction
extends AbstractAction
implements AppEventListener
{
protected ActionInterceptor interceptor;
protected IExceptionHandler exceptionHandler;
protected IActionStatusJudge actionStatusJudge = null;
public static final String TOOLBAR_SHOWNAME_KEY = "TOOLBAR_SHOWNAME_KEY";
public PubAction()
{
setShowNameInToolbar(false);
}
public String getBtnName() {
return (String)getValue("Name");
}
public void setBtnName(String btnName) {
putValue("Name", btnName);
}
public void setCode(String code)
{
putValue("Code", code);
}
public void handleEvent(AppEvent event)
{
updateStatus();
}
public void updateStatus()
{
boolean isEnable = isActionEnable();
setEnabled(getActionStatusJudge() == null ? isEnable : getActionStatusJudge().isActionEnable(this, isEnable));
}
protected boolean isActionEnable() {
return true;
}
public void setShowNameInToolbar(boolean isShow)
{
putValue("TOOLBAR_SHOWNAME_KEY", isShow ? Boolean.TRUE : Boolean.FALSE);
}
public void actionPerformed(ActionEvent e) {
Logger.debug("Entering " + getClass().toString() + ".actionPerformed");
beforeDoAction();
try
{
if ((interceptor == null) || (interceptor.beforeDoAction(this, e)))
{
try
{
doAction(e);
if (interceptor != null) {
interceptor.afterDoActionSuccessed(this, e);
}
} catch (Exception ex) {
if ((interceptor == null) || (interceptor.afterDoActionFailed(this, e, ex)))
{
if (getExceptionHandler() != null)
{
processExceptionHandler(ex);
}
else if ((ex instanceof RuntimeException))
{
throw ((RuntimeException)ex);
}
throw new RuntimeException(ex);
}
}
}
}
finally
{
Logger.debug("Leaving " + getClass().toString() + ".actionPerformed");
}
}
protected void processExceptionHandler(Exception ex)
{
new ExceptionHandlerUtil().processErrorMsg4SpecialAction(this, getExceptionHandler(), ex);
}
protected void beforeDoAction()
{
Method[] ms = getClass().getMethods();
for (Method m : ms)
{
Class<?> clazz = m.getReturnType();
if (AbstractUIAppModel.class.isAssignableFrom(clazz)) {
try
{
AbstractUIAppModel model = (AbstractUIAppModel)m.invoke(this, null);
if (model == null)
return;
LoginContext ctx = model.getContext();
if (ctx == null)
break;
ShowStatusBarMsgUtil.showStatusBarMsg("", ctx);
} catch (IllegalArgumentException e) {
Logger.debug(e.getMessage());
} catch (IllegalAccessException e) {
Logger.debug(e.getMessage());
} catch (InvocationTargetException e) {
Logger.debug(e.getMessage());
}
}
}
}
public abstract void doAction(ActionEvent paramActionEvent) throws Exception;
public ActionInterceptor getInterceptor()
{
return interceptor;
}
public void setInterceptor(ActionInterceptor interceptor) {
this.interceptor = interceptor;
}
public IExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public void setExceptionHandler(IExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
public IActionStatusJudge getActionStatusJudge() {
return actionStatusJudge;
}
public void setActionStatusJudge(IActionStatusJudge actionStatusJudge) {
this.actionStatusJudge = actionStatusJudge;
}
}
[TL;DR]
The problem is, in AWrapper and AType I have to duplicate pretty much whole function, where there is always the syntax:
public [TYPE/void] METHOD([OPT: args]) throws TestFailedException {
[OPT: TYPE result = null;]
long startTime = System.currentTimeMillis();
while (true) {
try {
beforeOperation();
[OPT: result =] ((WrappedType) element).METHOD([OPT: args]);
handleSuccess();
break;
} catch (Exception e) {
handleSoftFailure(e);
if (System.currentTimeMillis() - startTime > TIMEOUT) {
handleFailure(e);
break;
} else {
try {
Thread.sleep(WAIT_FOR_NEXT_TRY);
} catch (InterruptedException ex) {
}
}
}
}
[OPT: return result;]
}
Lets say I have 2 classes I don't own:
public class IDontOwnThisType {
public void doA(String string) { System.out.println("doA"); }
public String doB(); {System.out.println("doB"); return "doB";}
public OtherTypeIDoNotOwn doC() {System.out.println("doC"); return new OtherTypeIDoNotOwn();}
}
public OtherTypeIDoNotOwn {
public void doD() { System.out.println("doD"); }
public String doE() { System.out.println("doE); }
public OtherTypeIDoNotOwn doF(String string) {System.out.println("doF"); return new OtherTypeIDoNotOwn();}
}
So, I have an interface:
public interface OperationManipulator {
void beforeOperation(); //called before operation
void handleSuccess(); //called after success
void handleSoftFailure(Exception e); //called after every failure in every try
void handleFailure(Exception e) throws TestFailedException; //called after reaching time limit
}
Then interface that extends above one, "mimicking" methods of external classes, but throwing custom exception:
public interface IWrapper<T extends IType> extends OperationManipulator {
public void doA(String string) throws TestFailedException;
public String doB() throws TestFailedException;
public T doC() throws TestFailedException;
}
Then we have IType, which also extends OperationManipulator:
public interface IType<T extends IType> extends OperationManipulator {
public void doD() throws TestFailedException;
public String doE() throws TestFailedException;
public T doF(String string) throws TestFailedException;
}
Then, we have abstract implementations of above interfaces:
public abstract class AType<T extends IType> implements IType{
Object element; // I do not own type of this object, cant modify it.
Class typeClass;
long TIMEOUT = 5000;
long WAIT_FOR_NEXT_TRY = 100;
public AType(Object element) {
this.element = element;
elementClass = this.getClass();
}
/* ... */
}
Then, we override functions from the interfaces, excluding OperationManipulator interface:
Function not returning anything version:
#Override
public void doD() throws TestFailedException {
long startTime = System.currentTimeMillis();
while (true) {
try {
beforeOperation();
((OtherTypeIDoNotOwn) element).doD();
handleSuccess();
break;
} catch (Exception e) {
handleSoftFailure(e);
if (System.currentTimeMillis() - startTime > TIMEOUT) {
handleFailure(e);
break;
} else {
try {
Thread.sleep(WAIT_FOR_NEXT_TRY);
} catch (InterruptedException ex) {
}
}
}
}
Function returning normal reference version:
#Override
public String doE() throws TestFailedException {
String result = null;
long startTime = System.currentTimeMillis();
while (true) {
try {
beforeOperation();
result = ((OtherTypeIDoNotOwn) element).doE();
handleSuccess();
break;
} catch (Exception e) {
handleSoftFailure(e);
if (System.currentTimeMillis() - startTime > TIMEOUT) {
handleFailure(e);
break;
} else {
try {
Thread.sleep(WAIT_FOR_NEXT_TRY);
} catch (InterruptedException ex) {
}
}
}
}
return result;
}
And function returning object of type parameter:
#Override
public T doF(String string) throws TestFailedException {
T result = null;
long startTime = System.currentTimeMillis();
while (true) {
try {
beforeOperation();
OtherTypeIDoNotOwn temp = ((OtherTypeIDoNotOwn) element).doF(string);
result = (T) elementClass.getDeclaredConstructor(Object.class).newInstance(temp);
handleSuccess();
break;
} catch (Exception e) {
handleSoftFailure(e);
if (System.currentTimeMillis() - startTime > TIMEOUT) {
handleFailure(e);
break;
} else {
try {
Thread.sleep(WAIT_FOR_NEXT_TRY);
} catch (InterruptedException ex) {
}
}
}
}
return result;
}
The same goes for AWrapper, but the differences are:
constructor have class argument of stored type
object is cast to IDoNotOwnThisType instead of OtherTypeIDoNotOwn. Functions of this object also may return OtherTypeIDoNotOwn.
IDoNotOwnThisType is type that AWrapper is wrapping.
OtherTypeIDoNotOwn is type that AType is wrapping.
Then, we have implementation of these abstract classes:
public class AssertingType extends AType<AssertingType> {
public AssertingType(Object element) {
super(element);
}
#Override
public void beforeOperation() {
//System.out.println("Asserting type before operation!");
}
#Override
public void handleSuccess() {
//TODO: add to log file and log to output
System.out.println("Asserting type success!");
}
#Override
public void handleFailure(Exception e) throws TestFailedException {
//TODO: add to log file, log to output and throw exception
System.out.println("Asserting type failure!");
e.printStackTrace();
throw new TestFailedException();
}
#Override
public void handleSoftFailure(Exception e) {
//TODO: add to log file, log to output
System.out.println("Asserting type soft failure!");
e.printStackTrace();
}
}
And:
public class AssertingWrapper extends AWrapper<AssertingType> {
public AssertingWrapper (Object driver) {
super(driver, AssertingType.class);
}
#Override
public void beforeOperation() {
//TODO
System.out.println("Asserting wrapper success!");
}
#Override
public void handleSuccess() {
//TODO: add to log file and log to output
System.out.println("Asserting wrapper success!");
}
#Override
public void handleFailure(Exception e) throws TestFailedException {
//TODO: add to log file, log to output and throw exception
System.out.println("Asserting wrapper failure!");
throw new TestFailedException();
}
#Override
public void handleSoftFailure(Exception e) {
//TODO: add to log file, log to output
System.out.println("Asserting wrapper soft failure!");
e.printStackTrace();
}
}
So, we can use it like that:
AssertingWrapper wrapper = new AssertingWrapper(new IDoNotOwnThisType());
AssertingType type = wrapper.doC();
AssertingType type2 = type.doF();
Output:
Asserting wrapper before operation!
doC
Asserting wrapper success!
Asserting type before operation!
doF
Asserting type success!
The full working code is here:
LIVE
The problem is, I have always to write while, try catch etc in AType and AWrapper, can I somehow reduce code duplication? In the example i provided just 3 functions per class, but in my real code I have 50+ methods. Can I somehow wrap these functions so thepart that is repeating is not duplicated?
Your problem appears to be quite complicated, and I cannot claim to have been able to successfully wrap my mind around it, but I will give it a try, because it appears to be a very interesting problem and because I happen to have some experience in dealing with situations that yours appears similar to.
Please excuse me if my answer turns out to be completely off the mark due to a misunderstanding on my part.
So, what it appears that you are looking for is a general purpose solution for injecting your own code before and after an invocation where the invocation may be to any method, accepting any number of parameters, and returning any kind of return value.
In java there exists a dynamic proxy facility, which you can find under java.lang.reflect.Proxy.
With it, you can do the following:
ClassLoader classLoader = myInterfaceClass.getClassLoader();
T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass },
invocationHandler );
The invocationHandler is supplied by you, and it is of the following form:
private final InvocationHandler invocationHandler = new InvocationHandler()
{
#Override
public Object invoke( Object proxy, Method method, Object[] arguments )
throws Throwable
{
/* your pre-invocation code goes here */
/* ... */
/* invoke original object */
Object result = method.invoke( myObject, arguments );
/* your post-invocation code goes here */
/* ... */
/* return the result (will probably be null if method was void) */
return result;
}
};
So, I think you might be able to use that to solve your problem with the minimum amount of code.
Neither the creation of a dynamic proxy nor the call to method.invoke() perform terribly well, (you know, reflection is somewhat slow,) but if you are using it for testing, it should not matter.
I am solving this issue:
In my Java application (installed on Windows OS machine) I have to catch Win32 Event which is created by another application on same machine. This app is written in C++ and there is no way to change it. I have information that I have to use OpenEvent function. I started as is metioned in:
Calling OpenEvent fails through JNA
Here is my code:
public class WinEventListener {
private Logger logger = LoggerFactory.getLogger(WinEventListener.class);
static {
Native.register("kernel32");
}
public static native HANDLE OpenEventW(int access, boolean inheritHandle, WString name);
public static native int WaitForSingleObject(HANDLE hHandle, int dwMilliseconds);
public static native boolean CloseHandle(HANDLE hObject);
public static class HANDLE extends PointerType {
public Object fromNative(Object nativeValue, FromNativeContext context) {
Object o = super.fromNative(nativeValue, context);
if (INVALID_HANDLE_VALUE.equals(o))
return INVALID_HANDLE_VALUE;
return o;
}
}
static HANDLE INVALID_HANDLE_VALUE = new HANDLE() {
{
super.setPointer(Pointer.createConstant(-1));
}
public void setPointer(Pointer p) {
throw new UnsupportedOperationException("Immutable reference");
}
};
public void listen() throws Exception {
HANDLE handle = null;
do {
//logger.debug("Wainting for handle");
handle = OpenEventW(2, false, new WString("VLIT_SERVER_DATA"));
logger.debug("Handle:" + handle.toString());
Thread.sleep(1000);
} while (handle == null);
logger.debug("Handle obtained");
while(true){
int result = WaitForSingleObject(handle,Integer.MAX_VALUE);
if(result == 0){
logger.debug("Handle signalized");
VLITProcceserThread thread = new VLITProcceserThread();
thread.start();
CloseHandle(handle);
}
}
}
}
Basiclly I want in listen() method wait for HANDLE create by other program and if its created then wait for its signalized state, do some action and release handle.
BUt I have no success. Can anybody point me to right way?
Thans a lot!
If it is the opening of the handle that is failing it is most likely an issue with privileges. Is your program running as a service? I was trying to do something similar and was able to get this program running and working when i called it via a system call inside a program that was running as a service.
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.WString;
import com.sun.jna.FromNativeContext;
public class WinEventListener {
static {
Native.register("kernel32");
}
public static native HANDLE OpenEventW(int access, boolean inheritHandle, WString name);
public static native int WaitForSingleObject(HANDLE hHandle, int dwMilliseconds);
public static native boolean CloseHandle(HANDLE hObject);
public static class HANDLE extends PointerType {
public Object fromNative(Object nativeValue, FromNativeContext context) {
Object o = super.fromNative(nativeValue, context);
if (INVALID_HANDLE_VALUE.equals(o))
return INVALID_HANDLE_VALUE;
return o;
}
}
static HANDLE INVALID_HANDLE_VALUE = new HANDLE() {
{
super.setPointer(Pointer.createConstant(-1));
}
public void setPointer(Pointer p) {
throw new UnsupportedOperationException("Immutable reference");
}
};
public void listen() {
try {
HANDLE handle = null;
do {
handle = OpenEventW(2031619, false, new WString("event_name"));
if(handle == null) {
System.out.print("Handle is null\n");
}
Thread.sleep(500);
} while (handle == null);
while(true){
// 50 second timeout
int result = WaitForSingleObject(handle, 50000);
if(result == 0){
System.out.print("Handle signaled\n");
}
else if (result == 258){
System.out.print("Timed out\n");
}
else{
System.out.print("Handle not signaled\n");
System.out.print(result);
}
System.out.print(result);
//System.out.print(handle);
Thread.sleep(100);
}
}
catch (Exception exc)
{
System.out.print(exc);
//Thread.sleep(10000);
//writer.writeln(exc);
}
}
public static void main(String[] args) {
WinEventListener listener = new WinEventListener();
listener.listen();
}
}
I have defined my own expection class:
public class ProduktException extends Exception {
public ProduktException(String msg){
//null
}
public static void throwProduktNotCreatedException() throws ProduktException {
throw new ProduktException("Cannot be created!");
}
public static void throwProduktNotDeletedException () throws ProduktException {
throw new ProduktException("Cannot be deleted!");
}
}
My Problem is I do not know how to throw them when I try:
try {
...
} catch(ProduktNotDeletedException e) {
e.toString();
}
That does not work... But I want to have these structure! What is wrong?
I appreaciate your answer!!!
UPDATE:
My Problem is, I do not want to create several Exception Klasses I want to have all Exceptions in one class. Is there possibly a solution for that?
If you need to differentiate between different kinds of exceptions, just create 2 different exceptions, maybe something like:
public class ProduktException extends Exception
{
public ProduktException(String msg){
//null
}
}
Then have:
public class ProduktNotDeletedException extends ProduktException
{
....
}
and
public class ProduktNotCreatedException extends ProduktException
{
....
}
Then you can catch one or the other, or both.
try {
...
} catch(ProduktNotDeletedException e1) {
e1.toString();
} catch(ProduktNotCreatedException e2) {
e2.toString();
}
EDIT:
For a single class what I mean is:
public class ProduktException extends Exception {
boolean notDeleted;
boolean notCreated;
public ProduktException(String msg){
super(msg);
}
public boolean isNotDeleted() {
return(notDeleted);
}
public boolean isNotCreated() {
return(notCreated);
}
public static void throwProduktNotCreatedException() throws ProduktException {
ProduktException e = new ProduktException("Cannot be created!");
e.notCreated = true;
throw e;
}
public static void throwProduktNotDeletedException () throws ProduktException {
ProduktException e = new ProduktException("Cannot be deleted!");
e.notDeleted = true;
throw e;
}
}
Then in your try/catch:
try {
...
} catch(ProduktException e) {
e.toString();
if(e.isNotCreated()) {
// do something
}
if(e.isNotDeleted()) {
// do something
}
}
You need to either catch ProduktException, e.g.
try {
...
} catch (ProduktException e) {
e.toString();
}
or declare subtypes, e.g.
public ProduktNotDeletedException extends ProduktException
You'll probably want to pass the message in the constructor up, so add the following in your constructor:
super(msg);
The Syntax given below.
class RangeException extends Exception
{
String msg;
RangeException()
{
msg = new String("Enter a number between 10 and 100");
}
}
public class MyCustomException
{
public static void main (String args [])
{
try
{
int x = 1;
if (x < 10 || x >100) throw new RangeException();
}
catch(RangeException e)
{
System.out.println (e);
}
}
}
What you could do if you don't want to create multiple subclasses of your ProduktException for each different type of exception you need to throw is to include a code in the exception which will let you know what is wrong. Something like this:
public class ProduktException extends Exception {
private Code exceptionCode;
private String message
public ProduktException(Code code, String msg){
this.message = msg;
this.exceptionCode = code;
}
//Getters and setters for exceptionCode and message
}
Code can be an enum so that your application can know that each code corresponds to a specific "problem" (product not created, product not deleted, etc.). You can then throw your exceptions like this
throw new ProduktException(Code.PRODUCT_NOT_CREATED,
"Error while creating product");
And when you catch it you can differentiate based on the code.
catch (ProduktException ex) {
if (ex.getExceptionCode().equals(Code.PRODUCT_NOT_CREATED)) {
...
}
else {
...
}
}