I have a server application and two Swing-based client applications. We're developing them in eclipse and there's a separate project for each.
Many classes are shared. For example, the my.server package has some classes for both the server and the clients while others are for the server only. Although I prefer to put them in the same package because they are closely related and some of them rely on package visibility, I don't want to distribute classes that an application does not need as not only would it bloat the file size, but also it would be a security risk.
At the moment, each of the server and the clients has the same jars, which is a mess. Ideally, I'd like to automatically create jars based on dependency as following.
Server:
server.jar: classes used by Server only
server-client1-common.jar: classes shared by Server and Client 1
server-client2-common.jar: classes shared by Server and Client 2
Client 1:
client1.jar: classes used by Client 1 only
server-client1-common.jar: classes shared by Server and Client 1
client-common.jar: classes shared by Client 1 and Client 2, but not Server
Client 2:
client2.jar: classes used by Client 2 only
server-client2-common.jar: classes shared by Server and Client 2
client-common.jar: classes shared by Client 1 and Client 2, but not Server
I realize that you can do this manually using ant, but it would be a maintenance disaster. Is there a tool that takes care of such dependency automatically?
What do you mean by "maintenance disaster"? If you create an ANT script, just run it and it will compile and pack the jars for you.
As a more robust alternative, you might use maven. For something more lightweight, the built-in eclipse export tool might work.
I cannot present you with a ready-to-go solution. Here's an idea though: create an annotation or a set of annotations like this:
#jarselector(types='server')
class ServerOnly {
...
}
#jarselector(types='server,client1')
class ServerAndClient {
...
}
Then create your own ant task by extending the jar task (or maven plugin) or write your own task, that takes this annotation and packages classes according to the annotation, which you would then be using as a filter.
You would only have to create the task once - I've done it in the past, it is less complicated than it sounds and the problem sounds big enough to warrant the effort.
Afterwards you have to annotate all your classes once (or depending on your implementation only those classes the clients need, or only those that are not shared by every jar etc.). Whoever sees a class can see immediately what it is used for. When creating a new class you can easily add the annotation.
I really don't think there is a ready made ant task or maven plugin that does this.
Alternatively - if you really cannot change your package structure - you could also use multiple source directories to keep the packages but split the files in different directories. Eclipse doesn't care how many source directories you use. You would then need to adapt your build tool just once for the source directories and could then sort the files that way.
One of the best practices regarding building applications is to have one jar per project.
Maven, for example, uses this as default. You can trick it to do otherwise, but it is better to join them instead of "fight" them.
http://maven.apache.org/guides/mini/guide-using-one-source-directory.html
http://www.sonatype.com/people/2010/01/how-to-create-two-jars-from-one-project-and-why-you-shouldnt/
So, in your case you should create 6 projects:
Server, Client1, Client2, ServerClient1Common, ServerClient2Common, ClientCommon
In order to select the classes needed, I don't think there is a tool, and probably you should know better what is the common functionality.
Create the Common projects, and add them to the build path - dependencies. Then start moving your classes into the Common project, leaving them in the same package.
For example, create ServerClient1Common project.
For Client1, go to Configure Build Path -> Projects. Add ServerClient1Common. Remove all references to Server Project.
For Server, go to Configure Build Path -> Projects. Add ServerClient1Common. Remove all references to Client1 Project.
You should now have a lot of missing classes/imports. Try to solve them one by one.
At the end, you should be able compile the 3 projects and to obtain the jars you mentioned.
PS: Other strategies (like one uber-project with different build targets, or 3 projects with entwined ant/maven builders) are messier. There is maybe one exception - another way of splitting the classes, but I do not know if it applies to you: client1.jar, client1-interface.jar, client2.jar, client2-interface.jar, server.jar, server-interface.jar. This way you could use 3 projects with each having two target jars. To run client2.jar you will need server-interface.jar
Have a separate Eclipse project for each JAR that you're going to create. Then set up the dependencies on the "Projects" tab of the Build Path, for each of the top level projects. So, the "server" project will have "server-client1-common" and "server-client2-common" listed as required projects. And so on.
I've seen this model used by a number of different organisations, and I've always thought that this was the "industry accepted" way of doing it. It just works!
Related
I wrote two jars. Each one of them is responsible for sending different http/https request.
Each one of them uses, naturally, certain same classes. Like the ones that builds the requests or send them. The process might be a bit different, but still the general structure and classes names are the same.
Building different jars per request is a requirement from my managers! So using 1 jar for all my http requests is not acceptable.
Now, in my client program I need to send a request one time for JarA and one time from JarB. But compilation fails because, naturally, I am using very similar namings for the classes and methods.
For example, I have a UserData class in both jars. So when I try to use it in my client program, the compiler yells: "reference to SystemData is ambiguous".
I can start improvising specific classes names for each jar, but it is ugly...
How would you suggest to solve this problem?
If the classes are identical, pull them out into a third JAR and then have the client program reference the common JAR plus JarA or JarB.
If the classes are similar but not identical, then put them into different packages. You can have classes with the same names if they're in different packages.
Put common classes in a third jar and either bundle it in the two http jars or add it to the classpath at runtime (which is the best choice will depend on how you're deploying, etc.).
Firstly you have to decide which kind of architecture you are working with.
If managers asking you to have different jar's for sake of modularization - sure it's worth to make common jar which will contain all common classes.
I suppose you should have your project built with Maven, Gradle or another build system which will help you managing dependencies.
Another issue could be if you are supposed to do 'Microservices' architecture. Then code duplication is inevitable.
To overcome same class names when you have duplication - I would recommend to have for every module different package names then.
Use a build system like maven where one can have library dependencies, to a common third jar. It maintains a repository of versioned jars.
One solution is that - if you see a same class with same package in two different jars and both jars are required in your project,
Solution
you can download the source code of that duplicate class and creat keep the same in your project with package structure. So this way JVM loads your project classes first and give first preference to invoke your project class rather then other jar's class
I have an ant script that I use to build my J2EE application and create jar files. The problem is the following: Two jar files are necessary for the application to run.
commons-math-2.0.jar
commons-math-1.0.jar
However, I want to only use the 2.0 for a particular package inside the application with the rest of the application using 1.0. How can I build the application to only use the 2.0 version for example with a package name such as com.naurus.eventhandler.risk? Again, I'm using an Ant script, but if there's an easier way to do this sort of thing I'm willing to experiment. Thanks!
If the two jars contain different classes/packages there should be no problem to have all of them in the application classpath. It is then a matter of discipline not to use the classes from the one jar in the other package.
However I guess these two jars contain mostly the same classes/methods? There are many ways of using different versions of the same classes:
Using different ClassLoader instances. I would not qualify it as "easy", far from it means opening the door to a bunch of nasty bugs. (can be helped using a tool like OSGi)
Splitting the application in two processes, these process being launched in the same Ant target and using any mean (CORBA, RMI, REST, etc.) to communicate.
I would not advise using any of these methods though. It would probably be simpler to make all your packages use the same version. Is there any specific difficulty in doing so?
That will be problematic since both JAR files will end up in the same classpath when you deploy your J2EE application. You could achieve what you are trying to attempt with OSGI bundles, which allow each package to have separate dependencies. However, that is a relatively large refactoring of your application.
IMO, it would be best to either:
a) Duplicate the features you need from 2.0 (if the number is small and the license allows it, e.g., package individual classes).
or
b) Spend the time to upgrade the entire application to 2.0
You could use the manisfest in your jar to define the classpath.
http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Although honestly it seems a bit convoluted, but it is your requirement.
I am a C# developer and I am messing around with Java. In C# I would normally have my front end project and then when I need to add another layer to the project (i.e service layer etc) I would add a class library in the solution and add a reference to it.
What is the convention in Java? Do you add another Java project to the workspace and then reference the project? Or do you add a package to the project which contains your front end?
UPDATE
Sorry, I am using eclipse...hence the reference to 'workspace'
There's no real convention. When you say "workspace" you're not referring to Java, but rather a development environment (sounds like Eclipse). There are a number of ways to do it; you could do it the way you're suggesting, you could include the dependency via Maven, you could combine them all together in one project, etc.
Which to choose depends on your needs, who else will be consuming either the individual libraries or the completed project, and so on.
How to divide your source code depends a lot on the structure of your project. It is important to pay attention to a good code organization. You should keep classes for a common task or for a distinct application layer in own packages. You should watch for inter-package dependencies.
Using different "projects" (be it Maven or Eclipse projects) helps ensuring that you (your developers) do not violate structural boundaries because the compiler checks the dependencies (one project references the other project, like in C#/VS). Maven generates a build artifact (e.g. a JAR file) for every project.
To summarize, I think it is a good idea to create new individual projects for each program module in order to be able to manage the dependencies between the projects explicitly.
You are assuming everyone works with eclipse, it seems (your references to "workspace").
You can do anything you want, but keep in mind others might not be able to include 'separate' projects for various components of the application.
You can easily address that issue by using some build tool (ant, maven) to build appropriate jars for the various app components, like data-model, persistence, API, etc.
If you front-end is an RIA, might make more sense to develop it as a separate project, although not necessary. If your app is some sort of Java driven UI, you can still do whatever you want, in both cases make sure the UI components have their own package hierarchy.
Yes, I guess I would create a separate package. So your UI code might be in com.mycompany.app.ui, your service code in com.mycompany.app.service, etc. However you want to organize your classes is up to you. Java itself doesn't care what packages the classes are in. The packages just help to make the code more manageable for the developers.
Unlike most things in Java, there's no real convention defined for how to split up project.
In my experience, it makes sense to include code that serves a particular business purpose in a single project, and to separate out code that you intend to share between multiple projects, or code that is not specific to a particular business purpose (e.g. database access, JMS libraries, etc.), into a separate project.
If the UI and the server layer are being developed in a single project, which means packaged and deployed in the same WAR file, I'd create a new package for the service and add classes and interfaces as needed.
If the service layer is deployed separately, I'd add dependencies as a JAR to the web project. All I should need are clients for the service.
If you're working in Eclipse follow these steps:
1) Right-click the project and choose "Build Path"-"Configure Build Path..."
2) Switch to Libraries tab and click Add External JARs (or just Add JARs if they're already in the workspace).
3) Now you can either manually add import of the corresponding class, or just hit Ctrl+Shift+O (Source-Organize Imports) and Eclipse will do the job for you.
I suggest you can use netbeans then you can create a java class library,when you deploy your project,netbeans will generate jar files for you,and place them at the right location.I'm also a ms developer,hope it helps
I have a Java project that has both server and client packages. In addition I have a library package.
I use eclipse and have put everything in a single Java project, each section server,client and library are in separate packages, the problem is that when I export, everything gets added to the Jar file.
So I suppose I need two different projects, client and server, but what about the shared library files? What do I do about them? Do I actually need three different projects? It will become a little unwieldy as everything is actually related and I would like to keep them together.
I use eclipse and have put everything
in a single java project, each section
server,client and library are in
separate packages, the problem is that
when I export, everything gets added
to the Jar file.
This is the part that intrigued me, why are you exporting something that has both the client and the server? From a client-server perspective they are going to be distributed separately.
Do I actually need three different
projects? It will become a little
unwieldy as everything is actually
related and I would like to keep them
together.
Thanks to how IDEs can now manage dependencies across projects/modules, I don't think it looks as bad as you picture it. For example you can work simultaneously on the server code, and use its classes and interfaces from your client code, and reference JARs produced by the server project.
I'd like also to add that a 'Project' isn't the broadest encapsulation of code either, there is still a 'Workspace' that can contain a number of related 'Projects'. Other IDEs go for other wordings like 'Module' instead of 'Project'.
Closing thoughts:
For the least impedance path, I think you should separate the client and the server parts into two projects, and do the same think for the shared library in case you are compiling it from source i.e, not a 3rd party JAR.
So in the end of the day you will have 3 'products' from the compilation process and distribute them where they belong, with the 'library' duplicated on both distribution sides.
You can have a separate project for your shared code, and create a library (i.e. jar file) for that. Then, your client and server projects can both use the shared library.
Even better, you can use this shared library for other projects in the future.
Note:
Eclipse is just going to compile the source files into their respective class files and put then in the bin folder, or wherever you have your output folder set for the project properties. It doesn't create a jar file by default.
If you want to create jar files, the best way is to use a tool like ant. Then you would be able to create whatever jars you need, and structure it however you like.
Here's a link for reference:
Create Multiple JARs from Eclipse Project
You can create the separate project for client and server side, the shared package can be attach in the class path definition.
... the problem is that when I export,
everything gets added to the Jar file.
Is that really a problem? Maybe the shared code is an asset rather than a liability. Perhaps you should optimize the developer issues before worrying about the deployment problems that, around here, we've decided aren't problems after all.
So I suppose I need two different
projects, client and server, but what
about the shared library files? What
do I do about them? Do I actually need
three different projects? It will
become a little unwieldy as everything
is actually related and I would like
to keep them together.
We have a similar situation here and chose to embrace the shared code. Everyone gets the same code and choses what mode and configuration they need to start up.
If you check out our large-ish system (a bit over 5000 classes), you get the code for the servers (two main flavors), the clients (another two types), shared content (third party jars, visual assets, etc.) and site specific material (configuration files, start-up scripts and example data).
The result is that, after one checkout, you have the complete package for all of our primary locations, build scripts and Netbeans and Eclipse launch configs. As a result, you can go from an empty machine (with just an IDE) to a working client-server combination in about five minutes.
As a result, double-click the server icon and you launch a server process, running the site-specific configuration. Double-click the client and you launch a client process that's ready to connect to the server you just made.
Punchline: don't make development and deployment harder on yourself unless there's a very good reason. In our case, it was simpler, cheaper and easier to maintain the situation where we gave every installation the exact same package.
I have recently joined a project that is using multiple different projects. A lot of these projects are depending on each other, using JAR files of the other project included in a library, so anytime you change one project, you have to then know which other projest use it and update them too. I would like to make this much easier, and was thinking about merging all this java code into one project in seperate packages. Is it possible to do this and then deploy only some of the packages in a jar. I would like to not deploy only part of it but have been sassked if this is possible.
Is there a better way to handle this?
Approach 1: Using Hudson
If you use a continuous integration server like Hudson, then you can configure upstream/downstream projects (see Terminology).
A project can have one or several downstream projcets. The downstream projects are added to the build queue if the current project is built successfully. It is possible to setup that it should add the downstream project to the call queue even if the current project is unstable (default is off).
What this means is, if someone checks in some code into one project, at least you would get early warning if it broke other builds.
Approach 2: Using Maven
If the projects are not too complex, then perhaps you could create a main project, and make these sub-projects child modules of this project. However, mangling a project into a form that Maven likes can be quite tricky.
If you use Eclipse (or any decent IDE) you can just make one project depend on another, and supply that configuration aspect in your SVN, and assume checkouts in your build scripts.
Note that if one project depends on a certain version of another project, the Jar file is a far simpler way to manage this. A major refactoring could immediately means lots of work in all the other projects to fix things, whereas you could just drop the new jar in to each project as required and do the migration work then.
I guess it probably all depends on the specific project, but I think I would keep all the projects separate. This help keep the whole system loosely coupled. You can use a tool such as maven to help manage all the dependencies between the projects. Managing dependencies like this is one of maven's main strengths.
Using Ant as your build tool, you can package your project any way that you want. However, leaving parts of your code out of the distribution seems like it would be error prone; you might accidentally leave out necessary classes (presumably, all of your classes are necessary).
In relation to keeping your code in different projects, I have a loose guideline. Keep the code that changes together in the same project and package it in its own jar file. This works best when some of your code can be broken out into utility libraries that change less frequently than your main application.
For example, you might have an application where you've generated web service client classes from a web service WSDL (using something like the Axis library). The web service interface will likely change infrequently, so you don't want to have the regeneration step reoccurring all the time in your main application build. Create a separate project for this piece so that you only have to recreate the web service client classes when the WSDL changes. Create a separate jar and use it in your main application. This style also allows other projects to reuse these utility modules.
When following this style, you should place a version number in the jar manifest so that you can keep track of which applications are using which versions of your module. Depending on how far you want to take this, you could also keep a text file in the jar that details the changes that have occurred for each revision (much like an open source library).
It's all possible (we had the same situation some years ago). How hard or easy it'll be depends on your IDE (refactoring, merging, organizing new project) and you build tool (deploying). We used IDEA as IDE and Ant as build tool and it wasn't too hard. One sunday (nobody working+committing), 2 people on one computer.
I'm not sure what you mean by
"deploy only some of the packages in a jar"
I think you will need all of them at runtime, won't you? As I understood they depend on each other.