Skip navigation

The Java SE sources are downloadable from java.net, and you can change and extend them within the constraints of the relevant licenses. But building the whole of Java SE is a major undertaking. Here's how to build just the JMX API. The same ideas would apply to building other subsets of Java SE that are Java-language-only.

Update: there is now a purpose-designed build.xml that ships with the Mustang sources and that provides a simpler alternative to what's described here for the JMX API. See Joël Féraud's blog. But the process described here is still useful for building other subsets of the Mustang API.

Why is this interesting?

There are a number of reasons why you might be interested in modifying and recompiling the Java SE sources:

  • For research purposes, as covered by the Java Research License (JRL). This might be for your own curiosity ("I bet I could speed up the MBeanServer implementation"). Or it could be a good idea for a student project ("Add support for persistence to the JMX API"; "Extend the JMX API to provide support for reliable eventing"). Student projects that modify an existing medium-sized code base like the JMX API are much more instructive than projects that create new code from scratch, as they teach the invaluable skills of finding your way around a body of code. (I have lots more ideas for student projects, by the way!)

  • As an extension to the previous idea, you may be interested incontributing to the JDK code base. Obviously if you want to do this, you'll need to be able to build your modifications or extensions to existing code.

  • Finally, you might have run into a critical problem in the JMX API that you need to be able to fix right away. In general we make every effort to fix blocking problems promptly when they are reported, but because of the standard release cycle, it could be a few months before you see an update with your problem fixed. If you need the fix right now then you may be able to make it yourself under the terms of the Java Internal Use License (JIUL).

The JIUL applies to the current released JDK version, JDK 5.0 ("Tiger"), so the third reason above only applies there. The JRL applies to both Tiger and the forthcoming version, JDK 6 (Mustang), so for research you can choose which one is more appropriate. You can potentially contribute bugfixes and performance optimizations to Tiger or Mustang, though it's likely to be easier to contribute to Mustang. You can only contribute API changes to Mustang, since the Tiger API is frozen.

I should note that I am not a lawyer, and I'm not a spokesperson for Sun either, so read the licenses and their FAQs to be sure they cover what you want to do.

How do I build a subset of the JDK sources?

The instructions below are for building the JMX API in Mustang. Building a subset of Tiger is actually somewhat simpler, because you do not need to worry about "cross-platform support".

Apart from the details about RMI stubs at the end, the same considerations would apply to building other Java-language subsets of the JDK sources. If you need to change native code, then things become more complicated. Fortunately the JMX API doesn't contain any native code.

I tried out everything here on a machine running Microsoft Windows 2000. My usual development environment is Solaris, so trying this out on Microsoft Windows should have helped me avoid missing any "obvious" details that might not be so obvious to people who haven't worked on the JDK sources before! If you're running on a Unix-like environment such as Solaris or Linux it should be fairly obvious what to change.

  • To build Mustang, you'll want Mustang's JDK installation. This is all the more true if you are only building part of Mustang, because the JDK installation will supply the part you're not building. Download and install the latest Mustang JDK binaries fromhttp://download.java.net/jdk6/binaries/.

    Check the click-through license -- this is pre-release software and that limits what you can do with it, in obvious ways.

    You probably don't want to install this JDK snapshot in the default location. On Microsoft Windows, it is C:\Program Files\Java\jdk1.6.0\, which I think confers an unwarranted legitimacy on the installation. I put it inD:\jdk1.6.0\ -- you get to choose this in the dialogue entitled "Custom Setup". You don't need to change anything else in this dialogue.

    The installer covers both the Java SE Development Kit (JDK) and the Java SE Runtime Environment (JRE). In the "Custom Setup" dialogue for the JRE, you'll likewise probably want to change the default install location. D:\jre1.6.0\ was the location I chose.

  • Download the latest Mustang source from http://download.java.net/jdk6/. You'll need "JDK 6.0 Source under the JRL License", and you should take a moment to check out the license.

    The "JDK Binaries for Source Build 6.0" represents binary files such as Swing icons. You don't need these if you are building the JMX API, but if you're following these instructions to build some other subsystem you might.

    The source snapshot you downloaded will be called something likejdk-6_0-ea-src-b49-jrl-25_aug_2005.jar. It is an executable jar file. On Unix-like systems you might need to make it executable (chmod +x filename). Then execute it to install the complete Mustang sources.

    You get another chance to look at the magnificent JRL License before you click to accept it. Then you specify where you want to install the sources. I put this snapshot (b49) inD:\mustang-src-b49 to avoid confusion with any other Mustang snapshots I might download, but you might prefer to reuse the same directory even if you download several snapshots.

  • There's a huge amount of source code in this snapshot. To find your way around a bit, check out the README. All we're interested in here is the parts that build the JMX API.

    OS-independent Java platform classes can be found underj2se\src\share\classes. Frequently, subsystems have some classes under java.* or javax.*, including all of the publicly-visible API classes of course; and some implementation classes under sun.* orcom.sun.*. You can find out pretty readily where this second set of classes lives by examining the import statements in the first set.

    It turns out that the complete set of sources needed to build the JMX API consists of:

    • All classes under javax.management, including all subpackages, such as javax.management.timer andjavax.management.remote.
    • All classes under com.sun.jmx, including all subpackages except com.sun.jmx.snmp.com.sun.jmx.snmp represents the source for SNMP access to the JVM instrumentation defined by JSR 174; this is not directly relevant to the JMX API. You can build it if you want, but you don't need to.
  • I'd suggest copying the subset you want to build into a different directory rather than trying to build the files within the complete hierarchy. What I did was to create another directoryD:\mustang-jmx-src-b49 with a subdirectorysrc into which I copied thejavax\management and com\sun\jmxhierarchies. (Then I removed com\sun\jmx\snmp.) Of course you need to preserve the directory hierarchy, e.g. you should have src\javax\management andsrc\com\sun\jmx within your subset directory.

  • You now have a workspace within which you can build the JMX API. Here's how I went about it using NetBeans 4.1. I would expect the steps would be similar with other IDEs, although if your IDE does not support cross-platform use things will be a bit tricky. Cross-platform means that for example I am running NetBeans using JDK version 5.0 but I am telling it to compile and run my sources using JDK version 6. If your IDE doesn't support cross-platform use then you might still be able to run it under the JDK 6 snapshot you have downloaded. This is not necessarily as scary as it sounds -- at work I usually run NetBeans with the latest Mustang snapshot and there's only been one period of two weeks where it didn't work well. But, nothing is guaranteed with these snapshots, and the fact that the class file format has changed in Mustang may prevent your IDE from being able to compile against the JDK classes.

  • I first created a NetBeans project using File -> New Project -> Java Project With Existing Sources. I specified project namemustang-jmx-src-b49 and project directoryD:\mustang-jmx-src-b49, i.e. the directory where I had copied the source subset. I added the src subdirectory in the dialogue that says "Specify the folders containing the source packages and JUnit test packages." I specified a newtest subdirectory for JUnit tests. Once I clicked on "Finish" the project was created.

  • Then I set up cross-platform building and running. NetBeans is running on JDK version 5.0 but I want it to use the JDK 6 snapshot to compile and run the sources of this project. So I right-clicked on my mustang-jmx-src-b49 project in the Projects pane, and selected Project Properties -> Libraries. I needed to tell NetBeans about the JDK 6 platform, which I did using the "Manage Platforms" button on the top right of this dialogue. (You can also use Tools -> Java Platform Manager.) In the Java Platform Manager dialogue, I clicked "Add Platform..." in the bottom right. I selected D:\jdk1.6.0, which you'll remember is where I installed the downloaded Mustang JDK snapshot. If you downloaded the snapshot Javadoc you could specify it here too, but you don't have to. (I usually browse it directly from java.net.) Then Finish (for Add Platform) and Close (for Java Platform Manager), and you're back to Project Properties. You can now select the JDK 6 platform in the Java Platform drop-down list.

  • Also within the Project Properties dialogue, I needed to tell NetBeans to use compiled classes from within the project in preference to the classes in the JDK installation. This is subtle but important. Even if you have a class calledjavax.management.ObjectName in your classpath, the Java compiler and runtime will never see it because they will find the class of the same name in the JDK installation first. You need to change the boot classpath using the -Xbootclasspath option for both compiling and running.

    In Project Properties -> Build -> Compiling, I put the following in the "Additional Compiler Options":
    -Xbootclasspath/p:build/classes
    build/classes is the subdirectory within the workspace where NetBeans is going to put its compiled classes. (If you want to be squeaky clean you could put${build.classes.dir} here instead.) The/p means "prepend", i.e. this directory will be put in the boot classpath before the standard classes, which is what you want. I put the same thing in the "VM Options" within Project Properties -> Run.

  • Unfortunately it appears that this -Xbootclasspathoption doesn't get applied to the Java VM that is running the JUnit command to run tests. I had to edit some ant files by hand. I copied from nbproject\build-impl.xml the complete set of lines from
    <target name="-init-macrodef-junit">
    through to the corresponding </target>, and pasted them into the top-level build.xml file near the end. Then I added this line in the pasted text, just after the<junit ...> line:
    <jvmarg value="-Xbootclasspath/p:build/classes" />

  • Now to test that NetBeans really is compiling my sources and not falling back on the JDK classes, I added a trivialmain method tojavax.management.ObjectName:

        public static void main(String[] args) {
            System.out.println("hello, world");
        }
    

    NetBeans now flags ObjectName.java with a little green arrow in the Projects or Files panel because it is runnable. If I right-click on ObjectName.java in the panel, I can do "Run file". If this works, I know NetBeans is compiling and running my modified ObjectName class.

    Similarly, I can code a trivial JUnit test using File -> New File -> JUnit -> Empty Test. I just insert a test method that calls my new ObjectName.main method:

        public void testObjectNameMain() {
            ObjectName.main(new String[0]);
        }
    

    Now "Run file" on the test should successfully execute my test and print "hello, world".

  • If you've followed all these steps, you're now set up to play with the JMX API sources!

    One thing to watch out for, though, is that if you delete or rename a class, the compiler will still be able to find it in the original JDK classes. So if there are still references to the deleted class, they will continue to compile! If this proves to be a serious problem, you can get around it by preparing a "JMX-less" JDK installation. Copy your original JDK installation to another directory, and remove the javax.management andcom.sun.jmx packages and subpackages fromjre\lib\rt.jar within that other installation. Thejar command doesn't allow you to remove things from a jar, but because a jar is a special kind of zip file, you can use any tool for manipulating zip files instead. Then use the Java Platform Manager within NetBeans to replace the original JDK 6 platform with your JMX-less JDK platform. On the whole, this is a dodgy manoeuvre, and it's not guaranteed to work in the future. However, it's what we do within the JMX API team at Sun, and if it stops working at some point, I'll update this page. Also, I'd expect it probably wouldn't work for classes that the compiler itself needs to run. The compiler doesn't need the JMX API, but you might have a hard time doing the same thing withjava.util!

  • A final thing to watch out for is that the JMX Remote API includes some RMI stubs which are built using the rmic tool. Since the source for these generated stubs is not included in the JDK source download, you will contine to pick them up from the JDK's own classes. If you make a JMX-less JDK installation, or if you want to change the RMI interfaces the stubs come from ( RMIServer and RMIConnection), then for the JMX Remote API to work you'll need to generate the stubs yourself.

    You could add some <rmic>tasks to your build.xml, but it might be simpler just to generate the source code for the stubs and include the source in your project. For example, to make the RMIServer stub source you could use:

    rmic -keep -d src -bootclasspath build\classes;D:\jdk1.6.0\jre\lib\rt.jar
         javax.management.remote.rmi.RMIServerImpl
    
    (all on one line of course), then remove the filesrc\javax\management\remote\rmi\RMIServerImpl_Stub.classthat rmic will have generated. The procedure is the same for the RMI/IIOP stubs except you need the -iiopoption and the stubs will be generated inorg\omg\stub\javax\management\remote\rmi. Unfortunately rmic doesn't recognize-Xbootclasspath/p: so you have to give the full path to the classes in your JDK installation as shown here.

I hope this has been helpful! If you had a problem following these instructions, or would like to suggest improvements, or if you want to discuss API changes you are interested in, feel free to contact me at jmx-spec-comments@sun.com.

Update: if you want to build the whole of the JDK on a Microsoft Windows platform, Kelly O'Hair has documented out how to do it. The hard part is installing the necessary software.