1

After some research I cannot come across the best approach for this. There will be certain color classes that I would like to share amongst multiple projects. Let's call one of them EncryptedColor. Since it is used across multiple projects I don't want multiple copies of it in existence of course. Otherwise I would need to make sure that an update in one location would need to be updated everywhere. However, these classes are needed in some released SDKs that we provide to customers.

How could I design it such that I can use these classes but not provide them with the classes that they don't need access to from their SDK. I don't want useless classes to become visible and flood the smaller subset of classes that they really need to be seeing.

A couple approaches I have thought of so far but aren't quite ideal:

  1. Try and use a doclet structure that hides the calls within the javadoc such as doclava. Javadoc has not fully implemented its own hiding mechanism yet. As I understand this doesn't keep the functions from being visible, but it was mentioned in one spot that you would need reflection to use the calls. I don't see how just the javadoc does that so I must have been missing something.
  2. Android has designed themselves it seems to force reflection from some @hide attributes included in methods that they have in source code. But from the sounds of it, the system hides those and then uses a different jar when it is loading to make those visible at launch time. Probably not useful here.
  3. If I were to keep shared classes in the same package name I could access default and protected members, but...then I am keeping all my classes that use these in the same package name. Not quite ideal either, but it could be done in that manner if I needed to. Might get out of hand with large quantities of shared resources.

What approaches are taken typically in situations such as these? I haven't liked my findings and thought process thus far.

Jay Snayder
  • 4,298
  • 4
  • 27
  • 53
  • So some SDKs needs those classes but not all ? – ToYonos Nov 24 '14 at 16:38
  • @ToYonos There are applications for internal use that use those classes, external customer SDKs and various tools that make use of them as well. There are numerous classes of course, not just one. But I just wanted to focus on one of them for simplicity. Since it's used everywhere I want it existing in one place. I just don't want to have to expose these classes to the external SDKs where they are not needed. – Jay Snayder Nov 24 '14 at 18:14
  • OK. But one thing, you have said "external customer SDKs [...] make use of them" and "external SDKs where they are not needed". Am I missing something here ? – ToYonos Nov 25 '14 at 09:08
  • @ToYonos I'll simplify it. Project 1, 2, 3 use the color classes. Project 1 is an customer SDK. Project 2 and 3 are not. All use the color classes. Project 1 does not need to expose the color classes, and shouldn't. Otherwise it would flood the sixteen or so useful classes of the SDK with 120 color classes that it really shouldn't be bothering the customer with. – Jay Snayder Nov 25 '14 at 14:10

3 Answers3

2

Short answer : you can't hide/remove these classes as they are needed at runtime by your application.

In my opinon, you have 3 alternatives :

  • Change the classes access to "package private". Yes, doing that doesn't make it impossible to access them, but these classes won't be accessible directly.

  • Remove the classes and create an API. You want to hide the logic ? Remove it and provide it through a REST API for instance. Depending or your architecture, it could be difficult or impossible.

  • Create all the instance of these classes in a dynamic way, with Class.forName, using Spring or as in @Steve K answer, with Java's ServiceLoader. As a result, you will be able to remove these classes from the main jar and make them more private, in a way. Again, classes will be here but a little less accessible.

ToYonos
  • 16,469
  • 2
  • 54
  • 70
1

My suggestion that could work would be to implement your color classes as a service using the Java ServiceLoader You make an interface for your color classes, and implementations can be called using the ServiceLoader class. Then you simply separate your color classes into two packages - a public package you can jar up and distribute with your SDK, and a private package for those classes you want to be internal. The ServiceLoader will find all the color classes available so long as the jar files are in your project's classpath.

For example, if your color classes (as an example) had a common interface like this:

public interface MyAppColor {
    public int getRed();

    public int getGreen();

    public int getBlue();

    public int getAlpha();

    public void setRed(int red);

    public void setGreen(int green);

    public void setBlue(int blue);

    public void setAlpha(int alpha);

    public boolean isValid();

    public void doSomething(Object arg); 
}

Then you could have a bunch of implementing classes in a jar file, with a service descriptor file included in the jar at the path:

META-INF/services/com.my.app.MyAppColor

The text of that file is simply the list of classes in the jar that implement the interface - one per line:

com.my.app.MyPublicAppColor
com.my.app.MyEncryptedPublicAppColor
com.my.app.MyOtherPublicAppColor

etc. Then all you have to do is make a factory for instantiating the correct type, which could be as simple as this:

public class MyAppColorFactory {
    private static ServiceLoader<MyAppColor> serviceLoader = ServiceLoader.load(MyAppColor.class, null);
    public static MyAppColor get(String className){
        if (className != null){
            for (MyAppColor c : serviceLoader){
                if (className.equals(c.getClass().getName())){
                    return c;
                }
            }
        }
        return null;
    }
}
Steve K
  • 4,863
  • 2
  • 32
  • 41
  • But all the color classes implementation will be present in the SDK right, even in the customer one ? – ToYonos Nov 25 '14 at 14:19
  • Why would you add classes to your SDK that you don't want available? You can have two different jar files for the public and private ones, and simply not include the private jar with your SDK. – Steve K Nov 25 '14 at 18:29
  • According to the op, even the sdk needs all the color classes, so even the private package will be needed. In fact, internal projects and the sdk have the same needs, but the sdk must have some of its dependencies "hidden" from its user. – ToYonos Nov 25 '14 at 18:43
  • That wasn't what I got from his post. It sounded like the SDK needed a subset. He could, however, package the "public" classes in a jar with source code, and the private classes without, or something like that. – Steve K Nov 25 '14 at 22:12
  • [Quoting](http://stackoverflow.com/a/5761705/115145) one of the Android engineers: "ServiceLoader is stuff from the Java language that is not really relevant on Android. I recommend not using it." – CommonsWare Nov 29 '14 at 00:04
1

Deploying only needed code:

- Use Only The Needed Source In Development (1) (2)

Since you have an entire library and many deployments which each use different components, the easiest way to do what you suggest is to use only the sources that you need; not a single library. You can ignore the unused sources. This will only ship the needed code.

- Make The Library "Package Private"

This will allow the access only for the public components of the library and everything else will not be callable. But, it will still ship all the code.

- Create an API as a REST SDK

This will require web access, not desirable for performance code {any code really}. You will ship no sdk code with this method.

- Obfuscate the code

Easy with the correct tools. Obfuscation will change the class and method names in production code to gibberish. This will make the library basically unusable to anyone but you. This will ship all the code but it will be obfuscated

- Native API

You can compile java to machine code and use it in production or as the api. You can also create the api in a native language {not desirable}.

Community
  • 1
  • 1
miiiiiitchko
  • 510
  • 4
  • 11