Java: How to share common application / UI code among several applications - java

I have several applications that differ mostly based on resources. As of now, I'm copying the code around to each application. This can be problematic. An example, fixing a bug in one, and forgetting to update to the others.
I don't think creating a JAR is appropriate for this situation, as these are application specific UI classes, (actually android activity classes in specific) including the actual app start-up code.
It may be possible to include these source files into several packages, but then I have the problem that each file specifies a specific package name on the first line.
Most of the code is related to the UI and Activity processing. (The actual common code is already in a library). A similar question is posted here.
Are there any elegant solutions to this situation?

A jar is absolutely appropriate for this situation. You should split your application into layers, separating the application-specific classes from the shared code.

I solved this by going with Android Library projects. (Not sure of the details, perhaps they are ultimately jars) Check out details here, specifically the section 'Setting up a Library Project'.
I basically put in all my activity classes (except for the start-up one) into the library.
For true non-UI bound code, JARs, do seem to be the way to go.

I agree with artbristol.
I also recommend to use Maven and:
release the common jars to a corporate Maven repository
declare a dependency with specific versions on these jar artifacts
Like this you don't break applications if you do some incompatible changes.

Related

Find out which Java classes are actually loaded and reduce jar

Is there a way to automatically find out which Java classes are actually loaded (either during compile time, as far as that's possible, or during the runtime of an application), and to throw out all other classes from a JAR to create a smaller JAR? Does that actually make sense in practice?
I am talking about the application classes for an application JAR. Usually there are lots of libraries in an application, and an application rarely needs all features of those libraries. So I suspect that would make a considerably smaller application. In theory that might be done for example via an Java agent that logs which classes and resources are read by one or several runs of an application (or even just by java -verbose:class), and a maven plugin that throws out all other classes from a jar-with-dependencies. Is there already something like that?
Clarification: I am not talking about unused dependencies (JARs that are not used at all), but about removing unused parts of each included JAR.
Well, the Maven Shade Plugin has an option minimizeJar when creating an Uber-JAR for your application:
https://maven.apache.org/plugins/maven-shade-plugin/
But, as others already pointed out, this is quite dangerous, as it regularly fails to detect class accesses which are done via Reflection or other dynamic references.
It may not be a good approach automate, as application can use reflection to initialise objects or one JAR is dependent on another JAR.
Only way that I can think of is to remove each JARs one by one and check if application runs as expected. Then again in this approach all modules of the application has to be tested, since one module can work without particular dependency and other may not.
Better solution is to take care while developing. The application developer must be careful in adding a dependency and removing unwanted dependency after his/her piece of code is done.
Global strategy.
1) Find all the classes that are loaded during runtime.
2) List of all the classes available in the classpath.
3) Reduce your class path by creating copies of jars containing only classes you need.
I have done 1 and 2 part so I can help you.
1) Find out all the classes that are loaded. You need 100 % code coverage (I am not talking about tests, but production). So run all possible scenarios, so all the classes your app needs will be loaded and logged.
To log loaded classes try several approaches. Reflection, –verbose:class flag, also you can learn about java agent. It allows to modify methods during runtime. This is an example of some java agent code or another java agent example
2) To find all the classes available in jar, you can write a program. You need to know all places where application jars are placed. Loop throw these jars (You can use ZipFile), loop through ZipFileEntry entries, and collect all classes.
3) After that write a script or program that reassembles your application. For example, now you can create a new jar file for each library and put there only needed classes.
Also you may use a tool (again, you are a programmer, so write a program), which checks code for classes dependence. You do not want to remove classes if they are used for compilation. When I was a student, I wrote code alanyzer, which builds an oriented graph for classes dependencies.
As #Gokul Nath KP notes, I did this before. I manually change gradle and maven dependencies, removing one by one, and then full regression test. It took me a week (our application was small comparing to modern world enterprise systems created by hundreds of developers).
So, be creative, and in case of success, your project will be used by millions!

Pulling in a subset of classes from a sibling project

In my root project, I have many sub-projects:
common
dependant-1
dependant-2
...
standalone
In this scenario, common is a shared library. All other projects are dependant on it, with the exception of standalone. (standalone is actually a standalone client JAR).
What I would like to do is get 5 classes from common into the jar file produced in standalone. I only need those exact 5 classes (out of ~200) and want to avoid bringing common as a full dependency (along with all of common's dependencies). Granted it's an unusual setup, but I don't want to include classes that the client has no business with and the classes I am including just contain enum or static final.
So far, I have tried the following in the build.gradle for standalone:
jar {
manifest.attributes(
// .... Removed
)
with project(':common').jar {
include('com/classpath/ClassA.class')
include('com/classpath/ClassB.class')
include('com/classpath/ClassC.class')
include('com/classpath/ClassD.class')
include('com/classpath/ClassE.class')
}
}
This works very well for the standalone project, but tramples the other projects that were fully dependant on common; common.jar will now only ever contain the classes listed above, regardless of which dependant project.
(I'm guessing this is expected behaviour: in Gradle's configuration phase, it sees the specific configuration I have for common in standalone and applies that to common).
So, in short, what is the neatest solution to this? I'm thinking that I may need to provide a configuration in the build.gradle for the common project. I'm not sure how to do this yet (RTFM). I just wanted to check that there isn't a better approach to this?
EDIT: to answer some of alexvetter's questions.
I hadn't yet tried to include them from build/classes, but this did the trick (see the accepted answer).
I did consider creating a new common-base project. If there were much more than 5 classes that I needed, I absolutely would have gone this way. And yes, I only need the classes at runtime.
Just to clarify the last point... the standalone jar file is actually a JAX-WS client jar that we provide to another team. The reason I needed to inlcude these specific classes in the client JAR is so that the client knows what values to give to certain web service method calls. Ideally, I would have replaced all of the included classes with enum (like I mentioned, they are literally just static final definitions) and JAX-WS would have looked after everything. (I actually did this to replace one of the class files that I was including.) If I had done this for all the classes I needed to include, it would have triggered many more code changes for them (why this was a problem is a whole different story ;)
Following should do the trick:
from("${project(':common').buildDir}/classes/main") {
include('com/classpath/ClassA.class')
include('com/classpath/ClassB.class')
include('com/classpath/ClassC.class')
include('com/classpath/ClassD.class')
include('com/classpath/ClassE.class')
}
But as I already stated in my comments. This classes are only available on runtime and you should probably create a new project (e.g. base) which is a dependency of common and standalone

Add required plugins (dependencies) programmatically to an existing (plugin) project

In eclipse I can add required plug-ins (Dependencies) within UI (see screenshot above). This leads to an entry in the manifest.mf file.
My question is: How can I do this programmatically?
I imagine something like myProject.getManifest().addRequiredPlugin(new PluginImport(...
I already used the Plug-In Selection Spy and copied the used code. The problem is, that internal classes are beeing used there and I don't want to use internal classes. There must be a better way. Thanks in advance.
I don't believe this is possible.
Eclipse uses the manifest to load your plug-in, and probably doesn't read it again after that's done, so editing it would have no effect (since your code doesn't run until after your plug-in is loaded). As such, I doubt an interface has been provided to do this.
What are you trying to accomplish? I don't know of any use cases where trying to do this would be a good idea.

Java Package names and conflicts

a simple question but Ive realised im not sure of the answer for this one....
If I am creating an android application with a library package named
com.example.one
and then i create another app and include another package with the name
com.example.one
which has a slightly refactored class, could this cause any problems in either of the apps?
The reason i ask is recently I had a problem with some google source code and it was down to the fact that a device manufactorer had included the same libs in the custom OS that I had used in my apk, and it was not happy! (or so i was told)
If anyone can fill me in here, as i obviosuly dont understand something quite findamental here :)
thankx
EDIT: a good link on the diff between Android and Java package names http://blog.javia.org/android-package-name/
The classloader can't load two versions of the same class. It picks just one. But which one gets picked is undefined. So yes - it causes troubles.
Some platforms (java-ee) have options to specify jar precendence for these cases. I don't know about android.
Update: If my initial understanding is not correct, i.e. you are not having the same jar (library) twice on the classpath, but instead are starting 2 separate apps with different versions of the jar - then they won't interfere with each other (and hence no problems)
Actually, it shouldn't cause problems in the case of two separate Android apps. Android Apps run in Sandboxes, i.e. the Classloader of app A does not see any classes of app B and vice-versa.
This is obviously different for system wide-libraries. They are accessible by the classloader (of course) and will cause troubles if you have the same class in your app.
Yes, this can cause problems, but only if you have classnames that conflict within the package.
This doesn't seem to be an issue with your app though as you have two apps and two libraries (see answer from LordT)
Any easy workaround is to include the the app/library name in the package. For example:
com.app1.example.one
com.app2.example.one
That eliminates confusion & interference between the two packages.

Splitting Large GWT app into several modules

I have an app written with GWT and GAE where every supported city has its own app. Clearly this is not the best way to manage the map so I want to merge them all into one app. Currently my app is at the urls sub1.myapp.com, sub2.myapp.com, sub3.myapp.com, etc, and I want them to be at myapp.com/sub1 ,myapp.com/sub2, etc. All the supported cities share common code, so I'm going to put all the that code in one module, and have a different module for each piece of unique code block. Is this going about it the right way? How will the different modules interact?
Also, I currently have JSPs at sub1.myapp.com/listofsomesort and I would like to move these to myapp.com/sub1/listofsomesort. Is there a simple way to accomplish this?
By making a module with EntryPoint for each old application, in one and the same application. Each module has one 'welcome page' which you can put in different directories. All the shared code can go into another module. The shared code can be used by the inherit setting in other modules.
The only thing I bumped into was that when you deploy to GAE, ALL modules should have an entry point, also the library modules. I solved it by adding a dummy EntryPoint to them, that does nothing, but still searching for a better solution. See my question at How to deploy GWT Project containing GWT modules without entry points with Eclipse GAE plugin?.
This seems like the job for Code Splitting :) It might require some changes in the structure of your code, though - depends how tightly coupled your classes are. A compile report should tell you if your code splits up nicely, or if not, where the connections are.

Categories

Resources