3

I'm making use of SikuliX's API within my own personal library. The idea is to reference my library alone in external projects which incorporates the parts of SikuliX that I require.

Now, SikuliX throwns a FindFailed exception, which I required. I tried to do:

public class FindFailed extends org.sikuli.script.FindFailed {
    FindFailed(String msg) { super(msg); }
}

Which seemed to make sense. However, when attempting to use a throws statement in one of the methods:

import org.mylibrary.exceptions.FindFailed;

public static boolean clickFinishButton() throws FindFailed {
    pattern = PatternManager.loadPattern("my-image.png");

    screen.wait(pattern, 10);
    region = screen.exists(pattern);
    region.click(pattern);

    return true;
}

I still get an Unhandled exception type FindFailed warning. Changing it back to the original org.sikuli.script.FindFailed will of course work, however making use of try-catch in an external project will require me to re-add the relevant SikuliX jar file.

What I would like to do, is simply wrap the FindFailed exception that is being thrown by SikuliX and use it internally and externally with my library.

The primary goal of all of this is to wrap around another API with my own additional methods and such, so that when I reference this library, the later projects don't have to reference SikuliX's jar as well.

- - - - My Library - - - <—————— External Project
|                      |
|        SikuliX       |
- - - - - - - - - - - - 

As is it right now, I require to do the following:

- - - - My Library - - - <—————— External Project
|                      |                |
|        SikuliX       |                |
- - - - - - - - - - - -                 v
                                  SikuliX (Again)

So far I've changed things as follows which seems to work.

public class FindFailed extends Exception {
    public FindFailed(Throwable cause) { super(cause); }
}

I now don't extend any third party Exceptions. And instead I proceed by doing the following:

public static boolean clickNewScan() throws FindFailed {
    pattern = PatternManager.loadPattern("my-image.png");   
    region = screen.exists(pattern);
    try {
        screen.wait(pattern, 60);
        region.click(pattern);
    } catch (org.sikuli.script.FindFailed e) {
        throw new FindFailed(e);
    }
    return true;
}
Juxhin
  • 5,068
  • 8
  • 29
  • 55
  • 3
    you mentioned - _"making use of try-catch in an external project will require me to re-add the relevant SikuliX jar file which is not what I want"_- Since your custom exception is extending the exception class from library, you are going to need that library on classpath. There is no other way – Amit.rk3 Jul 24 '15 at 19:34
  • 1
    What you set to accomplish **might not be such a good idea** after all, even discounting the issue of FindFailed belonging to a different package: [Java theory and practice: The pseudo-typedef antipattern](http://www.ibm.com/developerworks/java/library/j-jtp02216/index.html) – Tobia Tesan Jul 24 '15 at 19:35
  • There are some valid points present. I may be able to clear up the question a bit more shortly by depicting my idea and why I'm doing this. – Juxhin Jul 24 '15 at 19:36

2 Answers2

4

You do this by wrapping all the calls in SikuliX their own interfaces. I don't know SikuliX, so I'll make a toy example.

package third.party.library;

public class Foo {
    public void doSomething() throws ThirdPartyException {
        // Their code
    }
}

Okay, so you want to wrap this functionality without depending on their library.

package juxhin;

public interface FooBehavior {
    public void doSomething() throws MyException;
}

Then, when you need their behavior, you can use your own implementation:

package juxhin; // YOU write this class

public class ThirdPartyFooBehavior implements FooBehavior {
    private final Foo foo;

    public FooThirdPartyFooBehavior(Foo theirObject) {
        this.foo = theirObject;
    }

    @Override
    public void doSomething() throws MyException {
        try {
            foo.doSomething();
        } catch (ThirdPartyException e) {
            throw new MyException(e);
        }
    }
}

Once you've wrapped their library behind all your own interfaces, then your classes only will only depend on your own interfaces, which means you won't have to worry about their exceptions. Their library will be completely removable as long as you reimplement these interfaces with a non-dependent implementation.

Note that MyException should not extend third.party.library.ThirdPartyException, because that won't help your problem; it should use the Exception(Throwable cause) constructor and remove it from the org.sikuli.script class hierarchy.


The bottom line, though, is that you still have to include the code included in SikuliX somehow. This is why tools like Maven exist, so that adding the reference to jars is very easy. For example, if your jar is dependent on SikuliX, then when you tell your new project to use your jar, it will automatically include the SikuliX reference without you having to do anything. You end up with dependency trees like this, which automatically do all this work for you:

Maven screenshot

I personally use Maven but there are other options like Ivy and Gradle that do the same thing - I'm not trying to advocate for any particular tool here, just advocating for using any dependency tool.

durron597
  • 31,968
  • 17
  • 99
  • 158
  • I like this idea quite a bit — granted I never used Maven (and got shouted at the fact that I never did) but I might have to just get over it. In this case I would like to keep it as simple as can be. The dumb alternative is to just add SikuliX in the external project aswell (which makes me cry a little bit :-( ) – Juxhin Jul 24 '15 at 19:50
  • @Juxhin The first half of my answer should work without **needing** any of the dependency management tools (though they will make your life easier, I promise), as long as you are building your jar properly, including the `SikuliX` code within your jar. See my edit for two other choices you may prefer over Maven. – durron597 Jul 24 '15 at 19:53
  • @durron597 - Yep I'm currently working over using the first half of your answer which will work in this case. However, like you said, a dependency tool is crucial in the long run – Juxhin Jul 24 '15 at 19:55
  • @durron597 - Indeed, mind taking a look at my quick update in a minute just to see if what I'm implementing it as is feasible in terms of maintainability or not. It does seem to work as intended though which I do like. – Juxhin Jul 24 '15 at 20:09
  • 1
    @Juxhin If you have a new question, you should ask a new question. See [Exit strategies for “chameleon questions”](http://meta.stackexchange.com/q/43478/200235). [Edits should not invalidate existing answers](http://meta.stackexchange.com/a/108500/200235). Also, be careful not to ask a [yes/no question](http://meta.stackexchange.com/a/183183/200235) (e.g. Is this approach okay?) I'm sure your approach is fine. If you try it, and it's not fine, then feel free to ask a new question. – durron597 Jul 24 '15 at 20:13
  • @Juxhin That approach looks fine. – durron597 Jul 24 '15 at 20:14
  • 1
    @durron597 I understand — I'll leave it as it is just incase someone else comes across the same query and wants to have an idea how I changed my code to suit my need. Thanks again for all your help. Much appreciated. – Juxhin Jul 24 '15 at 20:15
  • @durron597 so you are making another exception type...nice! What if then, another one have the same idea to come up with another library and do the same...and again, and again. It doesn't looks like a good solution, though you can truly represent, with the tons of exception types already available in the Java JDK, any behavior. Anyway, that's my "style"; I'm from the "unchecked exceptions" side – x80486 Jul 24 '15 at 21:44
  • @ɐuıɥɔɐɯ It's not as big of a problem as you think. You an always reuse your own custom exceptions. The frequency at which the scaling you describe occurs pretty slowly. How often are you **wrapping entirely new libraries?** A few times a year? You have a lot of flexibility here, add as many custom exceptions as your application needs and no more. – durron597 Jul 24 '15 at 21:50
  • @ɐuıɥɔɐɯ You present a good point, which is why durron suggested the dependancy tools. My idea is to do this once and once only. I do however understand what you mean and would have agree aswell. – Juxhin Jul 25 '15 at 09:20
  • 1
    @Juxhin there are still advantages to wrapping your third party libraries in this way... Swappability. It's easy to reimplement interfaces but it's not easy to go through all your code and change how you use third party objects. – durron597 Jul 25 '15 at 13:52
2

Extending from classes you don't own is never a good idea and should be avoided. Besides, it would make whoever handles your exception still have the jar that contains org.sikuli.script.FindFailed.

A better approach would be wrapping the exception like this:

public class MyFindFailedException extends Exception {
    MyFindFailedException(String message, Exception cause) {
        super(message, cause);
    }
}

And then use it like this:

public static boolean clickFinishButton() throws MyFindFailedException {
  try {
    pattern = PatternManager.loadPattern("my-image.png");

    screen.wait(pattern, 10);
    region = screen.exists(pattern);
    region.click(pattern);

    return true;
  } catch (FindFailed e) {
    throw new MyFindFailedException("something went wrong", e);
  }
}
Nina Satragno
  • 561
  • 3
  • 8
  • 3
    How's that different from the other...you also "don't own" `Exception` (please do not tell me that's because it comes with the Java SDK) – x80486 Jul 24 '15 at 19:40
  • I think you misunderstood the question. Main problem here is it's a third party Exception class. And OP wants to extend it, without having consumer to add the dependent libraries on their classpath explicitly. – Amit.rk3 Jul 24 '15 at 19:43
  • 1
    @ɐuıɥɔɐɯ `Exception` has a well defined, known implementation. You can easily check out the source. Overriding methods for which you don't know the implementation may break the parent class. Admittedly, in this simple example that would not be a problem. durron597's answer is spot on. – Nina Satragno Jul 24 '15 at 20:13
  • @Amit.rk3 I wasn't answering the question, I was referring to "Extending from classes you don't own is never a good idea"; and the same applies for anything else, the fact that something comes with the JDK doesn't means it's "holy" – x80486 Jul 24 '15 at 21:47
  • @ɐuıɥɔɐɯ : my comment was for this answer, not for your comment :) – Amit.rk3 Jul 24 '15 at 21:48