What's the point of a deep folder structure in Java (Maven)? - java

I've inherited a Java (Maven) project at work. I'm not a Java developer, but the project is now mine, nonetheless. When I clone (a la git clone) the repository, I notice the folder structure goes really deep before any .java files appear. For instance, the folder structure looks like this:
project_name
.git
.idea
src/
main/
java/
org/
bah/
co/
lab/
zeus/
apimanager/
RestClient.java
I've googled around, trying to find out why the folder structure goes so deep. After some research into Maven, my understanding is the default structure begins with /src/main/java. So, I'm curious why the previous (now incommunicado) developer structured this repo (and many others) like this. So as not to solicit opinion, please tell me: is there a technical reason the project is structured like this? There are literally no other .java files outside of the apimanager folder, so what technical reason would there be to bury everything so deep?

Maven is a tool that has certain opinions on where things should go; a default configuration. You don't have to follow it, but not following this default configuration has three significant downsides:
You do have to then configure maven to tell it about the alternative choices you made. Maven does not make this easy.
Other java programmers generally assume the defaults. If you have a good reason to deviate, go for it, but 'I do not like it' is not a good reason, as it'll be pointlessly increasing the learning curve.
The maven developers chose this structure as default for a reason. If you think it's a dumb reason, that's certainly possible and you may even be right, but then you're using a build tool written by folks who, (judging the book by its cover a little bit), according to you, make boneheaded choices about sane defaults. That's not a great place to be.
To explain each layer:
src
Indicates that these are source files: Compiled and generated stuff should not be in here, and the entire src tree should be in version control. Contrast to e.g. bin or build containing build artefacts, doc containing documentation, and who knows what other directories you need for other relevant parts of a repo.
main
A project can consist of multiple separately buildable artefacts and 'kinds' of product. For example, most projects include a bunch of code that exists solely for testing purposes (the unit tests). They live in src/test. The core product lives in main.
You can also have for example separate sources for an installer perhaps (src/installer), or a build plugin, or an annotation processor that needs to be built first and then it needs to be on classpath when compiling the main project, etcetera.
java
There's such a thing as split language projects, where some of it is written in language A and some of it in language B. For its worth, I think this layer is bad design; A file ending in .java gives away how one is to 'compile it', and this goes for just about every source file that needs a compiler applied to it: The extension says just as much as a folder name of java ever could. To show you a common contrast: Many projects have src/main/resources as well as src/main/java: Resources are 'compiled' simply by copying them over: Imagine your app has a text file containing a list of all US states with all zipcodes used in each state. Or png files with icon images for a GUI app. Such files are just as much part of your main application as the class files would be and should end up in the same place (inside the jar file), but to 'compile' them, you just.. copy em, you don't run javac to do this. That's what this level is about: What tool should be used to turn source files into distributable aspects?
co/lab/zeus/apimanager
This matches the java package structure. This is effectively a requirement applied by javac itself. The reason to use such a deeply nested package structure is simply because packages serve as namespaces: If there is a conflicting fully qualified name, all hell breaks loose: Java simply cannot handle this. Hence, java programmers ensure that such conflicts never happen by using a 'reverse domain name' structure: You'd stick your project in that package if you own the zeus.lab.co domain, thus ensuring nobody except other folks in your team who share control of that server could possibly be in conflict (and for those: They're in your team, talk to them to avoid conflict). For example, there are 3 different open source java projects all called spark. Had they all gone with package spark; (and thus, src/main/java/spark/Main.java as an example file), then for every java project you'd pick one of the 3: The other 2 you can never use in this project. Harsh, and pointless, which is why (almost) all java libraries use a reversed domain name as root package name, and then maven follows this package name in its directory structure because javac makes life extremely difficult if you don't do that.
That gets us to project_name/src/main/java.
org/bah
You made that up for hyperbole. Nobody hosts a proj on zeus.lab.co.bah.org. But if they do: Talk to the management that decided to assign that whopper of a domain name to a team. It's on them, not on the author of this project.

Maven is a build and dependency management tool that helps develop your application and manage all the lifecycle of your development process such as build, compilation, packaging, testing, etc. through command lines.
There is a convention on how a Maven project is structured:
└───maven-project
├───pom.xml
├───README.txt
├───NOTICE.txt
├───LICENSE.txt
└───src
├───main
│ ├───java
│ ├───resources
│ ├───filters
│ └───webapp
├───test
│ ├───java
│ ├───resources
│ └───filters
├───it
├───site
└───assembly
What is important to understand for the moment is the role a each files and folder and how to use Maven commands.
pom.xml : this file contains the structure and the information of your project, and your dependencies (external jars). This file is used by the commands you execute in Maven
src/main/java : contains your packages and your source code.
src/test/java : contains your test code
In your case, the structure of your project is due to the package name. Here, the name is org.bah.co.lab.zeus.apimanager and in Java a package is physically a nested group of folders. There is a package naming convention, but in most of the cases, it is up to you to choose the name you want to use.
As you are using IntelliJ IDEA, you can display your package with the options Compact Middle Packages.

Related

How to make Eclipse package ONLY required libraries?

After developing a java app in Eclipse, I would like to deploy it by packaging it into a runnable .jar with only the minimum necessary by the main method and its dependencies.
I have several packages in my workspace I work with too, but do not need to be in the resulting .jar file.
When I try to export, it clearly says that the required libs will be there, but also the other independent packages are inside too. (With the Export option happen exactly the same)
I choose to export only the Main class of the com.project... package, but also the test.project... has been packaged.
In the project I have both com... and test... packages obviously.
How could I force it to truly package only the required ones?
Thanks in advance.
TEMPORARY ANSWER (2019-07-03):
Seems that, for now, there is no way to achieve this automatically, thus the answer from #arnonuem seems a good workaround.
If better news, please feel free to improve this thread.
Thank you all.
I would create an ANT file for this specific task. There you can freely customize which packages should be compiled into the jar and which not.
Please inspire yourself reading this example.
For a general overview what i am talking about you could take a quick look into this.
https://howtodoinjava.com/ant/ant-build-jar-file-example/
Please focus on
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath"
includes="src/path/to/TheClassToBeIncluded.java" />
For more detailed information on how to include or exclude files or packages you should refer to the documentation over here:
https://ant.apache.org/manual/Tasks/javac.html
At the bottom of this page there is a list with valid build parameters.
First of all, we have to distinguish build and export.
Build transfers .java source code into .class byte code and mostly copies other resources. While doing that it usually merges all source folders into a single bin folder.
Export runs a build (or relies on Build Automatically) and then modifies the resulting .class files and other resources. Usually it packages them into one or more .jar files.
Therefore, our solution includes two steps:
build everything that is unwanted for export into a separate folder (or more)
export from a specific folder (or more)
For step 1, refer to this answer on Stack Overflow.
In a nutshell: Go to Project Properties > Java Build Path > Source tab > Allow output folder for source folders. This enables you to configure a specific output folder for each source folder in the centered viewer.
For step 2, we need to understand that eclipse's Runnable Jar File Export relies on a Launch Configuration.
So before exporting, go to Run > Run Configurations..., select the Classpath tab, remove the default User Entries and hit Advanced.... Now you can Add Folders containing your built classes.
You might want to use separate Run Configurations for internal testing and exporting.
I have struggled with this problem on and off for years, supposing it was just me who was failing to find the right solution. Possible solutions always seem to involve detailed manual configuration e.g. configuration of the build path, or selection of the folders from which classes are exported into a jar, or learning ant, but which still requires manual configuration. The problem is that the inter-dependencies between classes (and packages) are complex - imagine drawing a network diagram from import statements. Manual configuration is time-consuming, error-prone and, I think, infeasible except in simple cases. I am a bit stunned. If there is no automatic solution for selecting necessary classes, I suppose people are regularly exporting their entire code base and that the world is full of bloated jars ... (and, incidentally, without obfuscation, the entire source code base is thereby made available through reverse engineering).

Maven/Netbeans: open source files inside child modules

I have a multi-module maven project in this structure:
Parent
--ChildA
--src
--A.java
--ChildB
--src
--B.java
--ChildC
--src
many more...
I have Parent open as a project in Netbeans, I want to be able to use "go to type" (ctrl+O) to quickly access A.java (due to the large amount of java files we cannot remember which module each java file resides).
Is there a way to do this? As of right now I cannot use ctrl+O to find the source files unless I have the child module open.
I am told it should work similar to: ctrl-O for A.java, Netbeans will alert me it is in ChildA and ask me if I want to open that module. Is there a special setting for this operation? or maybe something I can put in the parent POM?
Update: seems like there are no good solutions. I managed to get what I needed by creating a module that depended on all the other modules and was able to index and access all the sources that way.
No way around that. Ctrl-O (or generally indexing of sources) is expensive and is done for opened projects only. There are large projects with hundreds of submodules, indexing them all all the time would require a lot of resources (CPU/memory/IO), limiting the scope to opened projects lets the user decide the scope of his work.
Some cheaper operations will still work (eg. hyperlinks).

In Java, should I be creating a new Package, Folder, or Source Folder?

There are a couple of questions on SO that sort of hit this, but I am totally new to Java development and I don't know the correct way to approach this.
I have a C# solution, containing two projects (my app, and a unit test project) and within the app, most things are put into folders eg. Interfaces, Exceptions etc.
I am trying to recreate this in Java / Eclipse, but I don't know how. I ended up with lots of packages, which sounds really bad. I also tried adding a source folder but that ended up being outside of the package.
Could anyone point me in the right direction?
Namely, which of those should I use to represent my unit test project/set of unit tests, and subfolders which exist just for organising stuff.
Edit: It also says use of the default package is not advised. What should I be doing?
Edit 2: Here is what it looks like. Does this look vaguely correct? My original C# solution is on the right.
In a typical java eclipse project, you will have one or more source folders (for example one for app code, one for your unit tests).
Each folder contains a package tree, typically starting with your base package, for example com.mycompany.myapp.
In order to avoid name collisions, packages names are usually start with the domain name of the entity who is the author of the code, starting with the top-level-domain and going backwards (more general to more specific). That way, each class fully qualified name is unique. For example if google creates a class named List, it will be known as com.google.List, and it will not enter in conflict with the existing java.util.List interface.
You can have a unlimited number of packages inside this base package, for example :
com.mycompany.myapp.persistence
com.mycompany.myapp.domain
com.mycompany.myapp.services
com.mycompany.myapp.web
It all depends on your project and the way you want to organize your code and your classes.
At the logical level, packages are named with dots as separator. They contain java classes.
At the physical on disk level, each package is a directory. The java classes are contained in .java files (most frequently one class per file).
In Eclipse a "source folder" is a folder inside your project that is known to Eclipse to contain java source files. It will be compiled included in the output (for example JAR file) when you build your project.
In Eclipse, you usually view them at the logical level, showing packages. When you tell Eclipse to "create a new package", it will create the directory for you. For example, if you tell it to create the com.mycompany.myproject package, it will automatically create a com folder containing a mycompany folder containing a myproject folder.
In java source tree structure must match package structure
so foo.bar package must be laid out in
src/foo/bar
Also default package may not be advised - but you can still use it - better to put things in a package though
In java different project development structure are flowed according to type of project.
So as you are new to java and Eclipse so it's better to install maven plugin and create maven project and choose a archetypes according to your project type like a standalone or web based.
The maven plugin will create the project structure including packages,test packages source folder etc. You can get more about project structure from this
Using the default package may create namespace collisions. Imagine you're creating a library which contains a MyClass class. Someone uses your library in his project and also has a MyClass class in his default package. What should the compiler do? Package in Java is actually a namespace which fully identifies your project. So it's important to not use the default package in the real world projects.

Why do Java source files go into a directory structure?

as weSuppose that I am creating a Java project with the following classes
com.bharani.ClassOne
com.bharani.ClassTwo
com.bharani.helper.HelperOne
com.bharani.helper.support.HelperTwo
with files put immediately under the folder 'src'
src/ClassOne.java
src/ClassTwo.java
src/HelperOne.java
src/HelperTwo.java
and compile them using the command
$ javac -d classes src/*.java (assuming that classes directory exists)
The compiler compiles these files and put the class files in appropriate sub-directories inside the 'classes' directory like this
classes/com/bharani/ClassOne.class
classes/com/bharani/ClassTwo.class
classes/com/bharani/helper/HelperOne.class
classes/com/bharani/helper/support/HelperTwo.class
Because the spec mandates that the classes should go inside appropriate directory structure. Fine.
My question is this: When I use an IDE such as Eclipse or NetBeans, they create the directory structure for the source code directory ('src' directory here) as well. Why is that? Is it mandatory? Or, is it just a convention?
Thanks.
Mainly convention. It makes sense for the source to mirror the binary structure.
Also, if you have two classes with the same name (but in different packages), how would you store the source if not in different directories?
Keeping the source in just one folder is fine for small projects, but once you have a larger project (hundreds of classes), grouping the source into packages makes things far more manageable.
Is it mandatory?
No
Or, is it just a convention?
Yes, to reflect your package structure in your source tree.
I always thought that Java's package is a little bit broken:
it seems to be hierachical, but it is not.
it is a simple (unique) prefix to define seperate plain namespaces.
I thought it was mandatory, but your experience suggests otherwise. Either way, it's just common sense, right? Large projects have so many source files - why make life more complicated by having different structures for your source and your class files?

In Java, where in the package/source hierarchy should resources be placed?

Say I have developed a game, and placed it in the package structure:
com.dxmio.games.breakout
Where then is the 'best practice' place to put resources like audio and images that the game uses?
You can always adopt a standard Maven approach to your project and put all application source files in:
{home}/src/main/java/com/dmxio/games/breakout
and then your resources live in:
{home}/src/main/resources/com/dmxio/games/breakout
and your tests then live in:
{home}/src/test/java/com/dmxio/games/breakout
This structure is a standard convention to structuring projects in the Maven world. It brings a lot of advantages with it, which you may want to look at. You can check out the resources section here: Apache Maven Guides - How do I add resources to my JAR
Alternatively :) the other answer's approach here is just fine...
I have seen this handled in a number of different ways:
Place your resources directly in a subdirectory under com/dmxio/games/breakout (e.g. /com/dmxio/games/breakout/images/foo.gif and /com/dmxio/games/breakout/images/bar.gif)
Place your resources in a jar along with your class files (e.g. foo.gif and bar.gif bundled in breakout.jar)
Place your resources in a separate 'resources jar' in a subdirectory under com/dmxio/games/breakout (e.g. foo.gif and bar.gif bundled in /com/dmxio/games/breakout/images/images.jar)
I tend to favor the last option.
You can then use the java.lang.Class.getResource() method to retrieve your resources.

Categories