23

I have a library with several packages-

lets say
package a;
package b;

inside package a I have public a_class
inside package b I have public b_class
a_class uses b_class.

I need to generate a library from this , but I do not want the Client to see b_class.

The only solution I know of is to flatten my beautifully understandable packages to single package and to use default package access for b_class. Is there another way to do so ? maybe using interfaces or some form of design pattern ??

Croc
  • 485
  • 5
  • 14

5 Answers5

11

If you reject to move the code to an individual, controlled server, all you can do is to hinder the client programmer when trying to use your APIs. Let's begin applying good practices to your design:

  1. Let your packages organized as they are now.
  2. For every class you want to "hide":

    • Make it non-public.
    • Extract its public API to a new, public interface:

    public interface MyInterface {...}

    • Create a public factory class to get an object of that interface type.

    public class MyFactory { public MyInterface createObject(); }

So far, you have now your packages loosely coupled, and the implementation classes are now private (as good practices preach, and you already said). Still, they are yet available through the interfaces and factories.

So, how can you avoid that "stranger" clients execute your private APIs? What comes next is a creative, a little complicated, yet valid solution, based on hindering the client programmers:

Modify your factory classes: Add to every factory method a new parameter:

public class MyFactory
{
    public MyInterface createObject(Macguffin parameter);
}

So, what is Macguffin? It is a new interface you must define in your application, with at least one method:

public interface Macguffin
{
    public String dummyMethod();
}

But do not provide any usable implementation of this interface. In every place of your code you need to provide a Macguffin object, create it through an anonymous class:

MyFactory.getObject(new Macguffin(){
    public String dummyMethod(){
        return "x";
    }
});

Or, even more advanced, through a dynamic proxy object, so no ".class" file of this implementation would be found even if the client programmer dares to decompile the code.

What do you get from this? Basically is to dissuade the programmer from using a factory which requires an unknown, undocumented, ununderstandable object. The factory classes should just care not to receive a null object, and to invoke the dummy method and check the return value it is not null either (or, if you want a higher security level, add an undocumented secret-key-rule).

So this solution relies upon a subtle obfuscation of your API, to discourage the client programmer to use it directly. The more obscure the names of the Macguffin interface and its methods, the better.

Little Santi
  • 8,563
  • 2
  • 18
  • 46
  • This is an ingenious solution, although as you mentioned, feels more like hindering the developer, my aim was to make it easier for them to use the API by meaning they could only see the parts of the API they are expected to use, I guess the only way to really do it is good documentation and having a factory that you tell them is the starting point and only including things in there that they need to use. I'm not too bothered if they do use the other methods, it's not like anything bad will happen, just trying to remove clutter from the public scope of the app. Thanks for the answer! – Ben Nov 11 '15 at 10:59
  • As mentioned in the above answer - I think dynamic proxies might be a better solution for this kind of case. – TR1 Nov 11 '15 at 15:49
  • 1
    Don't use an obscure name for Macguffin! If it's the only odd one in a nice and readable API it will certainly look suspicious. For some client programmers this might look like a "Strictly no admittance!"-sign which only hinders them from going to bed early. Use a serious name instead, for instance 'Caller', 'Instance', or 'MyAppNameContext'. This way a programmer would simply assume he's missing something and that your damn doc is incomplete. Don't make him fantasize about being a cool hacker. Remind him of being an idiot. Needless to say: I enjoyed this creative post :-) – Doe Johnson Nov 11 '15 at 16:06
  • @Doe Johnson "Don't make him fantasize about being a cool hacker. Remind him of being an idiot." You got it perfectly, my friend. Thanks! – Little Santi Nov 11 '15 at 16:26
  • I really like it. The psychology behind it is beautiful. Thank you. – Croc Nov 12 '15 at 06:50
  • @Croc "The psychology behind it is beautiful" ... really?! I liked the spirit of the question - it seemed you were trying to improve your public API by removing clutter and that's a goal I respect. This answer deliberately obfuscates a public API to make it difficult to use. Seems to me the psychology is to disrespect and confuse the API user (he is either a cool-hacker-fantasist or an idiot). – Stevie Nov 12 '15 at 09:16
  • 1
    @Croc I know it really does no good to me, but honestly, I have to admit Stevie's solution is much cleaner than mine (except for the fact that a SecurityManager could prevent to execute `setAccesible`). – Little Santi Nov 12 '15 at 09:32
  • I accept the remark,to be honest I waved the structural clarity I had and made it flat hirerchy. I don't like reflection.eventhough I agree it is a more correct technical solution. – Croc Nov 12 '15 at 14:39
6

I need to generate a library from this , but I do not want the Client to see b_class. The only solution I know of is to flatten my beautifully understandable packages to single package and to use default package access for b_class. Is there another way to do so ?

Yes, make b_class package-private (default access) and instantiate it via reflection for use in a_class.

Since you know the full class name, reflectively load the class:

Class<?> clz = Class.forName("b.b_class")

Find the constructor you want to invoke:

Constructor<?> con = clz.getDeclaredConstructor();

Allow yourself to invoke the constructor by making it accessible:

con.setAccessible(true);

Invoke the constructor to obtain your b_class instance:

Object o = con.newInstance();

Hurrah, now you have an instance of b_class. However, you can't call b_class's methods on an instance of Object, so you have two options:

  1. Use reflection to invoke b_class's methods (not much fun, but easy enough and may be ok if you only have a few methods with few parameters).
  2. Have b_class implement an interface that you don't mind the client seeing and cast your instance of b_class to that interface (reading between the lines I suspect you may already have such an interface?).

You'll definitely want to go with option 2 to minimise your pain unless it gets you back to square one again (polluting the namespace with types you don't want to expose the client to).

For full disclosure, two notes:

1) There is a (small) overhead to using reflection vs direct instantiation and invocation. If you cast to an interface you'll only pay the cost of reflection on the instantiation. In any case it likely isn't a problem unless you make hundreds of thousands of invocations in a tight loop.

2) There is nothing to stop a determined client from finding out the class name and doing the same thing, but if I understand your motivation correctly you just want expose a clean API, so this isn't really a worry.

Stevie
  • 7,957
  • 3
  • 30
  • 29
  • Thanks for the answer. While this does solve the problem, the question does specifically refer to android, and reflection isn't generally a good idea for android, especially if your use proguard. – Ben Nov 12 '15 at 11:26
  • No worries :) ... and you're right, pro-guard adds a wrinkle or two - you'd have to configure it not to obfuscate the class + constructor names of the classes you want to reflectively instantiate/invoke. – Stevie Nov 12 '15 at 11:49
  • Just wanted to add: I've yet to see convincing evidence that reflection should be avoided in Android - check the accepted answer (mine) in this question http://stackoverflow.com/questions/7224318/how-to-solve-the-xml-parsing-performance-issue-on-android ... note that the dsl4xml library uses reflection _heavily_, yet performs well in a tight loop on real devices (even old ones - this answer is years old) - roughly 15% overhead vs non-reflective code on Gingerbread/Dalvik, and things may even have improved with with newer Android's and ART. – Stevie Nov 12 '15 at 11:55
  • Looks like proguard + dexguard would handle the reflection stuff out of the box http://proguard.sourceforge.net/FAQ.html#forname – Stevie Nov 12 '15 at 14:08
2

When using Kotlin, you can use the internal modifier for your library classes.

Panos Gr
  • 667
  • 5
  • 13
1

If I understand correctly you are asking about publishing your library for 3rd party usage without disclosing part of your source? If that's the case you can use proguard, which can obfuscate your library. By default everything will be excluded/obfuscated, unless you specify things you want to exclude from being obfuscated/excluded.

hidro
  • 12,333
  • 6
  • 53
  • 53
  • Thank you for your answer - but its not a solution. I am using DexGuard - so the source code is well protected . I want the client which uses my library not to see b_class at all, no methods names and no "b_class" in the intellisense window. – Croc Jan 26 '15 at 10:56
1

If you want to distribute [part of] your code without the client being able to access it at all, that means that the client won't be able to execute it either. :-O

Thus, you just have one option: Put the sensible part of your code into a public server and distribute a proxy to access it, so that your code would be kept and executed into your server and the client would still be able to execute it through the proxy but without accessing it directly.

You might use a servlet, a webservice, a RMI object, or a simple TCP server, depending on the complexity level of your code.

This is the safest approach I can think of, but it also deserves a price to pay: In addition to complexing your system, it would introduce a network delay for each remote operation, which might be big deal depending on the performance requirements. Also, you should securize the server itself, to avoid hacker intrussions. This could be a good solution if you already have a server that you could take advantage of.

Little Santi
  • 8,563
  • 2
  • 18
  • 46
  • It's not about people being able to see 'the code' it's about people being able to access the methods, I'm happy for them to have the source code, but there are private methods that I don't mind them seeing, but good programming practice says in order to loosely couple library I should be limiting the entry points. I'm happy for them to read the private methods so long as they know they are private and therefore they shouldn't need to worry about them, there are just a handful of interfaces they need to be used. is there a way to do this without flattening the package structure? – Ben Nov 05 '15 at 15:35
  • @Ben I see, but my answer is still valid. If you want the Client party not to access your "private" code without flattering your packages to a single package with public and private API... you can completely hide your code into a remote server. Then, if you want, you can publish your javadocs with the open code. – Little Santi Nov 05 '15 at 16:17