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 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!
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.
This has been bugging me for years now, and I thought one of you fine people would know - in Eclipse's .classpath files, what is the combineaccessrules attribute of the classpathentry element actually used for?
I can see in the Java Build Path config dialog that it can be maniuplated, but I can't think of a good use case for it. If I muck about with the settings, or modify the .classpath file manually, it doesn't seem to have any effect.
I'm hoping someone else has put it to good use, and I can steal their ideas. Basically, it's an itch I'm trying to scratch.
With proper use of access rules you can prevent using "internal" and/or "non-api" classes and methods. When you add a class or package as Forbidden or Discouraged the compiler show an error or warning when you use that class or class from the specified package. For a longer introduction of access rules you should read this short article.
For using combine access rules imagine the following situation:
You have 2 projects, A and B.
On the classpath of project A there is a jar file that is exported. The jar contains some "stable api", "unstable api" and "non-api" public classes.
Project B depends on project A.
You do not allow using "non-api" classes in project A so you set some Forbidden access rules on those classes / packages.
In project B you do not allow using "non-api" as well, but you do want to get a warning when using "unstable api". In this case in project B you only have to set the additional Discouraged access rules if you check the Combine rules with the access rules of the exported project entries.
Access rules are handy little things, but dangerous. They exclude a source file from the project compiler but leave the file intact in the filesystem.
The project I work on has a bootstrap class in one of our source folders, but if we include the entire folder the project classpath it won't compile (it's a long story and the build process handles this).
So we use an eclipse access rule to exclude it and it never bothers us during development. This means we can't easily change the code, but it's one of those classes that literally hasn't been touched in years.
Combine Access Rules, judging by the JavaDoc, is a real edge use case. To use it you would have to have:
an access rule in an exported source entry of one project
a link to that project from a parent project
a need to combine the access rules of the sub project with the parent
I really can't say how it would be useful, but I hope that at least answers your "what is it" question :)
although i have never used it myself, a little bit of into can be found here.
whether the access rules of the project's exported entries should be combined with this entry's access rules
the access rules would be something like including "com/tests/**"