开发者

Why are project layout resources kept separate from Java sources?

开发者 https://www.devze.com 2023-02-07 12:57 出处:网络
Why does maven keep resources in a separate \"source folder\" from the Java sources? From my experience, in Java the resource files are mostly treated like Java source files which, when \"compiled\"

Why does maven keep resources in a separate "source folder" from the Java sources?

From my experience, in Java the resource files are mostly treated like Java source files which, when "compiled", just need to be copied as-is with the classes, and eventually packaged in the jar, and accessed by the classloader's methods getResource/getResourceAsStream, via the classpath.

Personally I find it a useless complexity to keep resource files separate from Java sources.

  1. What do you think?
  2. Is there a good reason why maven keeps resources separate from sources?
  3. Is there any counter indication in not using src/main/resources and src/test/resources and keeping resources in src/main/java and src开发者_开发知识库/test/java using maven?


One point that hasn't been brought up yet is that you are obviously used to seeing projects with only java sources in them. however, if you throw in some other source file types, i think the organization makes more sense, e.g.:

  • src/main
    • resources
    • java
    • groovy

each sub-dir has a specific classification of files:

  • java -> things that are compiled as java files
  • groovy -> things that are compiled as groovy scripts
  • resources -> uncompiled data used for whatever... (also, these may be filtered to add compile-time info)

also (as i've noted in some comments already), i don't usually make the resources directory flat. files may be nested into a package-like structure or into other sub-directories as appropriate (to my sense of organization).


for simplicity and easier access we keep some resources as well in the java source path. This makes it convenient for us when developing on the GUI level as velocity templates and such are close to the Controller Java Code. But you have to tell maven to include non java stuff which is in src/main/java by adding something like this to your pom file.

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                <webResources>
                    <resource>
                        <directory>src/main/java</directory>
                        <targetPath>WEB-INF/classes</targetPath>
                      <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                        <include>**/*.htm</include>
                        <include>**/*.html</include>
                        <include>**/*.css</include>
                        <include>**/*.js</include>
                      </includes>
                    </resource>
                    <resource>
                        <directory>src/main/resources</directory>
                      <excludes>
                        <exclude>**/log4j.xml</exclude>
                      </excludes>
                    </resource>
                </webResources>
                </configuration>
            </plugin>


What do you think? I think that the guys behind Maven should exercise a little "separation of concerns". The number one reason to use Maven is for dependency management, but why should a blender tell me how to peel my fruit? It makes no sense to me at all.

Is there a good reason why maven keeps resources separate from sources? No. In a java project, the duplication of package structure, not once, but three times, adds unnecessary work to the project, increasing the risk for errors and reducing the agility of the code.


I try to give an answer by myself.

What do you think?

It's a useless additional complexity. Thus is wrong: see below.

Is there a good reason why maven keeps resources separate from sources?

The only reason I might think of, is that for some platform this might be a good practice. For example in Mac OSX application, resources are packaged separately (in a different sub folder) than the binaries.

I think that "external" resources and configuration files, the ones that don't get packaged inside the final artifact (jar file) can have a good reason to be kept separate from the source files. So, when maven packages the jar, he knows that those files don't have to be included, because for example, we want them outside the jar in order to allow the user to edit those files as configuration.

But, for the things that are packaged together in the jar (like translation strings, and xml metadata, such as hibernate mappings and spring configuration) there is no good reason to have them in a separate location, unless we expect our users to change them manually after the deployment, as part of the configuration process.

Resources can be organized with the same package structure as for the classes, so if you have a class in the package x.y.z you may want to have the resources it depends on in the same package, as they represent the same "logical unit": in this case, having them in two separate folders leads to additional attention required during package refactoring and reorganization, since you want to keep the things in sync. The ClassLoader also provides the possibility to specify relative paths in the getResourceAsStream() method. So if you have the class x.y.z.MyClass, you can do getClass().getResourceAsStream("foo-bar.properties"), and the resources will be loaded from the same package "x.y.z". So it's very useful to keeps things together when they have a tight dependency.

For the external resources that needs to be kept separate also in the deployable artifact, it's a good thing to keep them separate, but in this case I don't see why maven treats the src/main/resources as a "java source folder" (maven-eclipse-plugin) since they actually must not be in the classpath but accessed through the filesystem as plain files, and especially you don't want those file to be included inside the jar during the maven build. This is the case of application icons, configuration files that you might want to place in /etc directory, and so on.

In conclusion, there's something wrong in how maven handles resources, in my opinion: if they are "external" resources, then there's no reason why maven packages them in the final artifact (jar). If they are not "external", then there is no reason to keep them in a separate "source folder".

Is there any counter indication in not using src/main/resources and src/test/resources and keeping resources in src/main/java and src/test/java using maven?

I don't know.

Most of the time I've used the default maven layout to play with resources, but in a couple of times I didn't; taking the precaution to declare the non-standard resources directory location in the pom (see resources and super-pom). It is possible to alter the maven project's directory structure specifying that in the pom:

 <build>
    <directory>target</directory>
    <outputDirectory>target/classes</outputDirectory>
    <finalName>${artifactId}-${version}</finalName>
    <testOutputDirectory>target/test-classes</testOutputDirectory>
    <sourceDirectory>src/main/java</sourceDirectory>
    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>src/test/resources</directory>
      </testResource>
    </testResources>
  </build>

And I didn't find particular problems with it.

I would like that maven guys think again about this convention, as having a simpler project structure helps the developer to concentrate more on the development and less on finding things around several folders in the project structure while browsing the application code.


The way I distinguish between the two is that the java folders default to allowing nothing to be built in the resulting jar, except the file types I list (e.g. *.class, *.html, *.properties if you're using Wicket), whereas all the stuff in resources will be copied in the build except the few exceptions I list.

Of course that's just my private convention, adhered to by myself.


1) What do you think?

I thinks, it's an excellent convention.

2) Is there a good reason why maven keeps resources separate from sources?

Yes. You follow the convention. Everyone, who has got your project code's access will know where to look for code and where for everything else. And certainly, where for test cases. And what will happen to which file when that plugin will be executed.

3) Is there any counter indication in not using src/main/resources and src/test/resources and keeping resources in src/main/java and src/test/java using maven?

There isn't a counter indication. It's matter of convention, nothing's wrong with the way you arrange your own code. In fact, if you ever created a Wicket project, you will see your HTML and your Java code stays side-by-side in Java package. But, it is just Wicket where you know the HTML is going to be by the side of Java files. But everything else goes in resources folder.


Maybe I'm the only one here who does not come from a Java background. I think that mixing resources and code is very messy. Separation of concerns make your project cleaner and easier to understand/maintain as it grows.

I try to apply my own directory convention to all my software development projects:

  • bin: final binaries used by user
  • build: intermediate binaries, they may be deleted after build
  • lib: external libraries
  • src: ONLY source code (in this case, Java source files)
  • resources: all resources (configuration files, xmls, images, html, etc)
  • docs: documentation

Rarely I've found a development context when I needed to change this directory structure.

Using Maven, if you want to make a quick setup, use the defaults. If you want to use your directory convention, you just need to change settings in the pom.xml as explained before. Be aware, however, that some Maven plugins consider you use default Maven directories for resources/source/output binaries and you'll need to adjust some plugin settings if you change these directories.


I think that code/resources separation is often useful:

  1. Packages must follow Java specification rules, for example reserved word, like 'int', is not allowed. Having illegal packages in source code folder would be confusing.

  2. Resources has instance nature, classes has, well, classes nature. For example you may have classes Continent and Country in the same package but resources better organize as tree:

    • africa/
      • morocco.txt
      • kenya.txt
    • europe/
      • poland.txt
  3. Resources structure, in my opinion, is more stable than code structure. Code refactoring happens often, classes move from package to package for better readability. Obligation to move resources on refactoring discourages developer from refactor.

  4. If separated resource folder is required even only for 1% of resource files, is reasonable to move remaining 99% to that folder and keep resources in single place only.

However, there are cases when keeping resources and java code together is useful. For example unit tests compares input and output - nice to have file with input and output in the same folder as unit test code.

0

精彩评论

暂无评论...
验证码 换一张
取 消