Inheritance and visibility across projects - java

edit: I only ever used Eclipse to program Java, so all of the following (and all my knowledge on Java) is dependent on how Java is programmed in that environment.
I have two eclipse projects: Project A with class X and Project B with class Y. Class Y from project B extends class X from project A.
public class Y extends X // In short B is dependent on Project A
Class X is public and it has a nested class O.
public class X {
class O { // default access modifier
}
}
In my setup, class Y can instantiate O as long as O is not private. Meaning, even if O has a default access modifier, Y can still access O's members and variables. This is confusing to me because I thought default classes meant that foreign classes have access to it only if they shared a common package.
So the conclusion I get from this is that the default package in every project must be the same or connected in some way. Am I correct in thinking this? And if this is correct, will changes made in the package of one project be reflected on the package in the other?
And this presents the main problem I'm dealing with. I want to control access to class O such that in my example, I want Y to not be able to instantiate O. Only way I can do that now is to set the visibility of O to private, but this also restricts other classes from the same project (project A) from accessing O. I want class Y from project B (which I thought had a different package from project A) not be able to access O but some other arbitrary class from the same project as Y/O to have access to O with no problems. How can I do this?

A few different questions here so I'll enumerate them and answer individually. Also, I'll assume that by project you are referring to something like a project in Eclipse.
Am I correct in thinking this?
Correct, if you have multiple projects (e.g. JAR file build artifact Eclipse projects), each with a default package (e.g. src/main/java/Foo.java in two projects) default scope (i.e. package-private) classes will be able to see each other and their respective public, protected, and package-private methods and fields.
And if this is correct, will changes made in the package of one project be reflected on the package in the other?
Correct, assuming that the changes of the upstream project are visible to the downstream project.
How can I do this?
Strictly speaking, you can't unless, as you said, you make it private. And even then, you can circumvent it. However, what you can do is choose meaningful package hierarchies that other coders are unlikely to use. For example, names such as com.acme.myproject.subfolder are common for this reason. But somebody could still create a parallel folder in their own project and call your package-private classes. That being said, for private member classes, they could change the accessibility of that member, thereby circumventing you. While that may sound scary, if you want truly secure code, you really ought to use secure authorization to remote services. The purpose of making something package-private is to prevent it from being part of your API, rather than enforcing some true security. In fact, often this behavior is desirable. For example, suppose I have a package-private class at src/main/java/com/acme/myproj/Foo.java that I want to unit test. The Foo class is package-private because I don't want to make it part of my public API. So, I can just create src/test/java/com/acme/myproj/FooTest.java and voila, I can now execute unit tests against my package-private class Foo.
I hope that explains things.

Related

Using shared class libraries internally, but not providing access to them in released SDK

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:
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.
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.
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.
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.
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;
}
}
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}.

A Java method that can only be called by its own class or by other subclasses

I'd like my class to have a method that can only be called by itself or by its subclasses.
The closest thing is protected access, but it also allows other classes in the same package to call the method, which I don't want.
Is there a way to achieve this, or should I consider some sort of package refactoring instead?
It seems to me like private won't let subclasses use the method.
See In Java, difference between default, public, protected, and private
There is no such thing. But you can move the class in an empty package and use protected.
Short Answer: Refactor your Packages
Explanation:
The java spec considers the package relationship to be a closer relationship than that of a subclass. This is because I can extend any class as long as I import it.
If you want to be sure the method is not accessible even by subclasses outside the package, use the default visibility modifier.
Source
Stack Overflow reference
To accomplish this, put your class in a package of its own and make methods default protection. There won't be any other classes in the package to see it to call it via package access.
Consider also, that if you seal the jar that the class is in, only you control what is in a given package and have effectively locked any others from creating a class in the package that you define - no one else will be able to introduce a class into the package and break the encapsulation.
Sorry, but protected is your only choice if you want subclasses to be able to call or override a method without making it public. If you do not want other classes in the same package to have access for some reason, move your class to a new package. But if you are thinking that the package and access control keywords form some kind of DRM (i.e. digital rights management) system rather than simply a code management and class "contract" system, you are mistaken. Think of access control keywords as nothing more than documentation which the compiler has some ability to verify when other code fails to comply with the stated intent as expressed by the documentation.

Make a class extends another class at runtime

There is a library have a base class (let's call it CBase) that performs some tasks and one can create classes that extends this CBase class.
The behavior of the CBase is not enough for me, so I would like to create my own CBase class (let's call it MyCBase) that have the same methods and members but these methods don't do the same thing.
Until now everything is ok. But what blocks me is that I would like to replace CBase by MyCBase. However, I have a lot of classes that extend CBase and I don't want to change them all.
Is it possible to replace CBase by MyCBase at runtime ?
So that
public class A extends CBase {}
becomes
public class A extends MyCBase {}
Can I perform this using code enhancement ? (like we do to add methods to a class at runtime. Is it also possible to change inheritance this way ?)
Thank you for your help !
EDIT
I would like to write a plugin for a framework, this is why I would like to change inheritance at runtime. This way users of the framework can use my plugin without changing their source code (changing the inheritance of their classes from CBase to MyCBase)
EDIT 2
Is it possible to do like this: ?
CtClass cc = CtClass.forName("pkg.AClass");
cc.setSuperclass(CtClass.forName("mylib.MyCBase"));
cc.compile();
I'm not expert. Probably you could extend ClassLoader. But I highly recommend don't do it. The replacement will touch many of your classes but it will be clear in code reading and app execution.
I think there is also room for architecture improvement since you have so many classes extend CBase. People are trying to remove dependencies from other libraries or keep it really small. Because in this case you could easily switch to another library or add your own functionality.
I dont think you can change the extends of a class at runtime. I would suggest to change the extends of the objects or build an interface, which contains all the things your need
Changing all derived classes is a simple matter, provided you control their source code:
Create a new class in your project. Call it CBase, and put it in the same package as the library class.
Use the rename/move refactoring of your IDE to rename CBase to MyBase. This will have the IDE rename all references to the renamed/moved class ...
Write the code for MyBase, extending from CBase.
If you can not do this (for instance because some derived classes are in a library you do not control), you replace the implementation of CBase with your own. Simply create a class of the same package and name in your project (the classloader searches the classpath in order, and uses the first class of the proper package and name it finds). This approach however is very brittle, as the compiler can not check binary compability between the old and new version of CBase. The JVM will check this compatibility when classes are loaded, but since classes are only loaded when needed, its hard to test your changes. (Which is why I do not recommend this approach if there are other options).
You could also change the classes as they are loaded my manipulating the class file, that that's going to be even more brittle, and the compiler would allow you to use any additional features MyBase might have. ==> Definitely not a good idea.

What's the proper way of declaring project constants in Java?

This may seems a silly question for Java developers, however, I'm new to Java, and my background is from low level c.
I used to include an header file with all the constants that were relevant for my projects. (usually #define's).
I'm working on a big Java project now, and there a few constants I need to make global (they fit in more than one class, and used in various parts of the project )
It makes it hard for me to decide where to put it, should I declare the same constant few times, one in each class ?
A lot of framework, uses XML files to declare constants & definitions for the framework (Hibernate, Log4J, etc.) Is it wise to use this kind of technique in my project ? if so, how can it be done easily ?
As with many things, there are many ways to do it. One thing you should not do is declare them multiple times - that's just plain silly. :P
Everything has to be in a class in Java, so either:
Pick a "main" class (say I have a project called "FTPServerApp" - I could put them there)
Create a "Util" class that contains all of them
When you figure out where to put them, declare them all this way:
public static final [type] [NAME_IN_ALL_CAPS] = [value];
This will
make them available to all your project code, anywhere (public)
only one copy of the value exists across all instances of the class (static)
they cannot be changed (final).
The ALL_CAPS_FOR_CONSTANT_NAMES, separated by underscores, is the convention in Java.
So, if this was declared in a class called FTPServerAPP, and you had a constant called SERVICE_PORT it might be:
public class FTPServerApp {
public static final int SERVICE_PORT = 21;
...
}
...and you would access it, from any class, like this...
FTPServerApp.SERVICE_PORT
Take a look at enumeration types (http://download.oracle.com/javase/tutorial/java/javaOO/enum.html) They are supposed to provide a mechanism to supply constants without defining a concrete class (or an Interface with the desired constants, as is another option that people use).
One other technique I find helpful (similar to the FTPServerApp example given above) is to define a Context for whatever subsystem/component/etc... that holds not only the constants needed by components in that system, but can hold any state that you want to make more visible or don't want individual components to hold. I believe this is along the lines of one of the GoF patterns, but it has been so long since I have looked at that book that I can't be certain (and I am too lazy to look it up right now!)

Providing Java library, but hiding some classes

I am developing an application in Java ME that I want to provide as a library. Is there no way to hide classes that I don't want everyone to use, but is essential still in order for the library to work?
UPDATE:
I get that I can omit the public specifier, but how can I structure the library itself while developing without creating different packages? I like to view different packages as different folders simply which allows me to structure the code in a good way. However, in some cases I might need to access classes in other packages so this is rather tricky. What does packages really represents? One idea might be to create "interfaces", but these has to be declared public so that means that foreigners might also implement the interfaces intended only for some processes inside the library, correct?
For setting up your library API you'll want to protect anything you
don't want exposed. Do do this just omit the access modifier:
class fooBar {
// do stuff here
}
This will set the class access as 'default' which allows access from
within the same package as well as from any classes which subclass
fooBar.
Within your classes you will also want to lock down any access on your methods and members by marking them either private, protected or omitting the modifier so that they are 'default' as required.
private will allow access from the containing class only;
'default' (no modifier) allows from within the containing class and containing package; and
protected will allow access from within the same class, package and any subclasses.
For anything that you have exposed (public) it is also good practice to mark it as final if it's not designed to be overridden.
Basically, lock down everything as much as you can. Smaller API's are easier to use and harder to break. If you find something needs to be exposed in the future, do it in the future. It's much easier to expand an API rather than deprecate parts of it.
If Java 9 is possible, use Jigsaw modules. If not, put every class on the same package, with package-level access for hidden classes, and use Maven modules to organize them.
I've done exactly that in my project called coronata, a Wii Remote java library. Almost all classes are in package com.github.awvalenti.bauhinia.coronata, but on different modules (which appear as projects on the IDE).
Visible classes are public. They are in modules:
coronata-api
coronata-builder
coronata-demos
coronata-lib
Hidden classes have package-level acesss. They are in modules:
coronata-common
coronata-implementation-bluecove
coronata-implementation-wiiusej
You can make the classes package protected which only other classes in the same package can see.
If this isn't feasible, then you can use ProGuard to mangle the classes and hide their implementations.
Lets consider an Example:
If you have a class A, that you want to hide, and a class B, that uses the functionality of class A, then you can do this:
class B{
//Attribute and Methods
//Inner class A
class A{
//Methods and Attributes.
}
}
After doing this, you can create an Object of class A inside a method of class B and hence use it. Though the class will be hidden from other classes, it could still be used.
Yes, there is.
Simply don't declare those classes public. In other words, omit the public keyword like so:
class Internal { // rather than "public class Internal"
...
}
By default, classes are only accessible within the package where they are defined.
You need to make the classes that you don't want exposed protected. This will make them non usable from client code. Read more in the official docs

Categories

Resources