java8 tools.jar annotation processing with apt - compilation

As java programmers we have inherited a legacy app which is now being upgraded to java8. The App runs on an embedded jre which is shipped along with our App.
We also ship tools.jar with the App, which is used to:
1) Compile .java files at run time; e.g. com.sun.tools.javac.Main.compile("SomeCustomClass.java"...).
2) Process annotations using the apt tool( package com.sun.mirror.apt); e.g. 'int aptReturnCode = com.sun.tools.apt.Main.process(myAnnotationProcessorFactory...);
Problem is that the apt tool has been removed from tools.jar in java8 -> http://docs.oracle.com/javase/7/docs/technotes/guides/apt/GettingStarted.html#deprecated
and we cannot use some thing like 'JavaCompilerTool compiler = ToolProvider.getSystemJavaCompilerTool()' because we only have access to our embedded jre and no jdk on client systems.
As a workaround we are compiling the SomeCustomClass.java into a jar file externally and then adding it to our app's classpath but its not viable long term as these class's come from the client and can change all the time.
I can think of the following ways around this problem:
1) Ship 2 tools.jar an old one for annotation processing and one java8 for compiling code at run time, but no idea how to avoid any naming conflicts etc.
2) Rework the myAnnotationProcessorFactory code that is using annotation processing to use javax.annotation.* instead of com.sun.tools.apt.* . As this is legacy code it will be quite error prone.
Can you guys think of any other ways around it ?
Many Thanks

Related

Is there a simple kotlin compiler out there for windows without extra bloated IDEs?

I have tried the download folder for kotlininc, and did everything the instructions said. And I'm still getting an error saying:
error: Could not find or load main class org.jetbrains.kotlin.runner.Main
Is there a lite weight simple kotlin compiler for windows which is easy to install?
something like javac
or g++
etc
If you don't want an IDE, I would recommend using a build tool. Kotlin supports Ant, Maven, and Gradle.
Of course, using the plain kotlinc command-line compiler is the simplest, but you already linked to it. If you need help figuring out what you're doing wrong with that, create a new question and explain/show what you've tried.

Can I use RxJava2 and RxAndroid in a single java class library?

I'm tasked with creating an SDK that can be consumed from both Android & Java applications using ReactiveX programming. I already have an android project using RxAndroid created, but now I need to extend it with RxJava2.
The question I'm facing is whether I should create 'regular' java class library and use it for both scenarios or create 2 separate packages (which would mean a lot of duplicate code + maintenance).
Is this even possible? And if so, is it a good practice?
whether I should create 'regular' java class library and use it for both scenarios
Yes. What I would do to start is simply change your Android library project to be a standard Java library and replace RxAndroid dependency by RxJava. Most code should still compile. Code which doesn't will mostly use schedulers provided by RxAndroid and can be changed to take Scheduler parameters.
Then create an Android Library project which depends on the Java Library and put the RxAndroid-specific code there.
As an addition to #AlexeyRomanov's answer, feel free to check out this library which could be used for both Android and Java projects: https://github.com/JakeWharton/RxRelay.
Its basically an extension to RxJava, but it might give you a solid idea where to go. Good luck!

Java Doclet API change for jdk 8

I am a newbie to Java. I was trying to upgrade to jdk 1.8 and found the following errors on doing a "gradle test":
/u01/sv/home/sv900t1/sv_test/Test_Suites/SeleniumLibraries/src/main/java/com/csgi/svtest/selenium/CustomWriter.java:57: error: cannot find symbol
h2("Class "+classDoc.toString());
^
symbol: method h2(String)
location: class CustomWriter
/u01/sv/home/sv900t1/sv_test/Test_Suites/SeleniumLibraries/src/main/java/com/csgi/svtest/selenium/CustomWriter.java:58: error: cannot find symbol
printHyperLink(classDoc.toString()+".html","","Class description<br>",true);
^
symbol: method printHyperLink(String,String,String,boolean)
location: class CustomWriter
I referred to http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java/
and http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/com/sun/tools/doclets/formats/html/SubWriterHolderWriter.java/
(our code imports this: import com.sun.tools.doclets.formats.html.SubWriterHolderWriter;)
and found that many apis like h2(), printHyperLink(), hr(), table(), tableHeaderStart(), tableHeaderEnd(), tableEnd(), pre(), strong(), preEnd(), ul(), print(), li(), ulEnd(), printHtmlHeader(), center(), today(), printTop(), navLinks(), printBottom() and printBodyHtmlEnd() have been removed.
Is there a quick workaround that can enable us to bypass the symbol errors?
Or should we replace the missing apis with existing ones. This looks like a lot of work to me - being an entrant. Are there any existing examples on how to do that? I have searched the internet a lot, but could not find anything useful.
The code in CustomWriter.java is for outputting a Javadoc page using custom System Test tags. Any help is appreciated - we are short on time.
Well here's the problem. The classes in the com.sun.tools.* packages should be treated as internal APIs. There are clear warnings in the Java documentation that say that you should not write code that against these APIs.
For example:
Why Developers Should Not Write Programs That Call 'sun' Packages
Closing the closed APIs
In Java 8, the header of the class that your code is trying to use says:
This is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This code and its internal interfaces are subject to change or deletion without notice.
(The bolding is in the original!)
It didn't say that in Java 7 (ouch!) Indeed there are versions of the Javadoc FAQ which seem to encourage people reuse the standard doclet classes. Unfortunately, Oracle have decided to close off these classes, and have also made some breaking API changes which reinforces this, whether or not that was the intention of the changes
What can you do about it? Unfortunately, there is no easy solution:
Maybe you could find an truly open source Doclet codebase that you could modify.
Maybe you could find a commercial vendor or consultant who will do the work for you.
Or maybe you just "suck it up" and rewrite your code to work with the latest version of the (internal) APIs. And live with the possibility that you may need to take more pain in the future.
Or ... you could reinstall Java 7 on your build / test boxes and use it (just) for running your custom doclets.
UPDATE - It has been pointed out that the "rule" above is for sun.* packages. However:
The document doesn't say anything about com.sun.* packages, so it is not valid to infer that they fall into the same category as java.*, javax.* and others that are explicitly stated to be reserved for Java supported APIs.
There are other examples of com.sun.* packages that are explicitly stated to be NOT supported. For example, Oracle's "Compatibility Guide for Java 8" says things like this:
The com.sun.media.sound package is an internal, unsupported package and is not meant to be used by external applications.
The JDK internal package com.sun.corba.se and sub-packages have been added to the restricted package list and cannot be used directly when running with a security manager.
The apt tool and its associated API contained in the package com.sun.mirror have been removed in this release.
Conclusion, even if there is no explicit statement that com.sun.* packages are internal, Oracle is >>now<< treating them as internal when it suits them. In some cases, retrospectively.

How to compile jdk itself

I want to compile jdk itself. I mean, I want to modify String.class in jdk to see created string objects in the system. Is there any way to modify classes in the jdk? When I try to modify source by modifying rt.jar, I got the error.
java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:394)
at java.lang.System.initProperties(Native Method)
at java.lang.System.initializeSystemClass(Unknown Source)
Probably there is a signature problem.
That doesn't look like a signature problem. It looks like you changed something that's causing Hashtable to dereference a null pointer. Review the change you made and see why it's doing this. Recall that Java keeps internal references to String constants in some conditions. I'm guessing you broke one of those.
Is there any way to modify classes in the jdk?
Well, you can download, modify and build the OpenJDK releases of Java 6 from source. There's information on how to do this on the OpenJDK site.
But beware that changes to low-level Java classes (such as String) can have effects that are hard to a non-expert to understand. And the consequence could well be a JVM that fails in a way that makes println or printStackTrace() inoperative.
There is maybe another way: you download java.lang.String original source, doing your modifications and compile only this class.
When you start your main programm be aware when loading classes: first load your String class then the java runtime classes. Refer to the java manual and the -Xbootclasspath/p options to do it in the proper order.
When installing a JDK you may choose to install the sources as well. Do so. Or download the sources separately. Then
expand the src.zip and get the String.java file.
create a new project containing the String.java in package java/lang.
change it accordingly to your needs.
just compile it.
put the class into the bootclass path of your JDK. See More infos on Bootclassbath.
run your app.
java -Xbootclasspath/p:<changed String classpath> -cp <regular classpath> <your application main class>
But changing the JDK might not be a good idea and you are not allowed to ship a changed JDK (at least up to 1.6) due license restrictions.
And yes, your problem is most likely somewhere else. Remember select isn't broken ;-)

Best way to install a custom cocoa framework

I have a custom framework that, following the advice in Apple's Framework Programming Guide >> Installing your framework I install in /Library/Frameworks. I do this by adding a Run Script build phase with the following script:
cp -R build/Debug/MyFramework.framework /Library/Frameworks
In my projects I then link against /Library/Frameworks/MyFramework and import it in my classes like so:
#import <MyFramework/MyFramework.h>
This works very well, except that I always see the following message in my debugger console:
Loading program into debugger…
sharedlibrary apply-load-rules all
warning: Unable to read symbols for "/Users/elisevanlooij/Library/Frameworks/MyFramework.framework/Versions/A/MyFramework" (file not found).
warning: Unable to read symbols from "MyFramework" (not yet mapped into memory).
Program loaded.
Apparently, the compiler first looks in /Users/elisevanlooij/Library/Frameworks, can't find MyFramework, then looks in /Library/Frameworks, does find MyFramework and continues on its merry way. So far this has been more of an annoyance than a real problem, but when runnning unit tests, gdb stops on the (file not found) and refuses to continue. I have solved the problem by adding an extra line to the Run Script Phase
cp -R build/Debug/MyFramework.framework ~/Library/Frameworks
but it feels like sello-taping something that shouldn't be broken in the first place. How can I fix this?
In the past months, I've learned a lot more about frameworks, so I'm rewriting this answer. Please note that I'm talking about installing a framework as part of the development workflow.
The preferred location for installing a public framework (i.e. a framework that will be used by more than one of your apps or bundles) is /Library/Frameworks[link text] because "frameworks in this location are discovered automatically by the compiler at compile time and the dynamic linker at runtime."[Framework Programming Guide]. The most elegant way to do this is in the Deployment section of the Build settings.
As you work on your framework, there are times when you do want to update the framework when you do a build, and times when you don't. For that reason, I change the Deployment settings only in the Release Configuration. So:
Double-click on the framework target to bring up the Target info window and switch to the Build tab.
Select Release in the Configuration selectbox.
Scroll down to the Deployment section and enter the following values:
Deployment Location = YES (click the checkbox)
Installation Build Products Location = /
Installation Directory = /Library/Frameworks
The Installation Build Products Location serves as the root of the installation. Its default value is some /tmp directory: if you don't change it to the system root, you'll never see your installed framework since it's hiding in the /tmp.
Now you can work on your framework as you like in the Debug configuration without upsetting your other projects and when you are ready to publish all you need to do is switch to Release and do a Build.
Xcode 4 Warning
Since switching to Xcode 4, I've experienced a number of problems with my custom framework. Mostly, they are linking warnings in GDB that do not really interfere with the usefulness of the framework, except when running the built-in unit-test. I have submitted a technical support ticket to Apple a week ago, and they are still looking into it. When I get a working solution I will update this answer since the question has proven quite popular (1 kViews and counting).
There's not much reason to put a framework into Library/Frameworks, and it's a lot of work: You'd need to either do it for the user in an Installer package, which is a tremendous hassle to create and maintain, or have installation code in your app (which could only install to ~/L/F, unless you expend the time and effort necessary to make your app capable of installing to /L/F with root powers).
Much more common is what Apple calls a “private framework”. You'll bundle this into your application bundle.
Even frameworks intended for general use by any applications (e.g., Sparkle, Growl) are, in practice, built to be used as private frameworks, simply because the “right” way of installing a single copy of the framework to Library/Frameworks is such a hassle.
The conventional way to do this is to have your framework project and its clients share a common build directory. Xcode will search for framework headers and link against framework binaries in the build folder first, before any other location. So an app project that compiles and links against the header will pick up the most-recently-built one, rather than whatever's installed.
You can then remove the cp -r and instead use the Install Location build setting to place your build product in the final location, using xcodebuild install DSTROOT=/ at the command line. But you'll only need to do this when you're finished, not every time you rebuild the framework.
Naturally, when you distribute your framework it should be installed in /Library/Frameworks; however it seems odd to me that you're doing that with the test/debug versions of your framework.
My first instinct would be to install test versions under ~/Library, as it just makes setting up your test and debug environment that much simpler. If possible, I would expect the debug/test framework to be located in the build tree of the version I'm testing, in which case it's installed as a Private Framework for testing purposes. That would make your life much simpler when it comes time to deal with multiple versions of your framework.
Ultimately, it doesn't matter where the framework is located as long as your application or test suite loads the correct version. Choose the location that makes testing/debugging/development easiest.

Resources