I've been having terrible luck trying to get this to work, so I'm hopeful someone can help here.
In Java, I need to be able to take an HTML page with JavaScript within it and detect any JavaScript errors without, preferably without executing the JavaScript code.
I found this article:
Javascript parser for Java
And I've attempted to figure out how I'm supposed to use Caja to do this, but I'm having a difficult time finding any documentation with working examples of anything close to what I'm doing.
As a result I took a look at Nashorn also referenced in that article. I found a few examples which show how to execute JavaScript code from Java, but this doesn't process the whole HTML page. Even then, the execution doesn't seem to include the ability to validate common JavaScript functions (e.g. It hadn't heard of "alert").
Can anyone recommend something that might be able to do what I want, and point me in the right direction for their documentation or give me an example?
jshint as a standalone product seems to be a good fit for this:
it can run in java inside rhino (see https://github.com/jshint/jshint/)
a nodejs package exists (see https://www.npmjs.com/package/jshint)
it works with nashorn but it's quite tricky
I will only cover the technical difficulties around 3rd solution as I finally managed to make it work too...
Spoiler alert: "alert()" is not detected yet... Solution nb 2 will help there...
You first need to grab this specific release of jshint: https://github.com/jshint/jshint/releases/tag/2.4.4
Anything later than v2.7.0 will fail for now and I personally gave up patching intensively prototypes and namespaces... Releases from v2.4.4 until v2.6.3 work without modification but are limited in functionalities.
In the release notes, it's specifically written that "support for the Nashorn JavaScript engine" is working on this release. I'm using JDK8 nashorn 1.8.0_45 for this test.
Next step is to extract from this release this single file jshint-2.4.4/dist/jshint-rhino.js
Now you need to run nashorn/jjs in scripting mode and you need to be specific about the single file you wish to verify. In solution 2 (nodejs based) you can do multiple files or a complete hierarchy below a folder...
Create a simple file file.js:
function(){}
Now run the following command (please note the presence of -- ):
jjs -scripting jshint-rhino.js -- file.js
This will give you the following output:
Missing name in function declaration. (file.js:1:9)
> function(){}
So this covers the how to run jshint in a simple manner with nashorn... With the 3rd solution, at least you can find missing semicolons and several typical errors. But it's not a silver bullet and to me it's not a real alternative.
My personal preference would be to stick to solution 2 only. If you've the possibility to install either nodejs or iojs on your dev platform, go and grab https://www.npmjs.com/package/jshint. Not only will you be able to do more than the 3rd solution, you'll also be able to configure a jshintrc file as described at http://jshint.com/docs/
I am trying to create a simple server program to handle http requests. So with minimum search, I stumbled upon the oracle documentation for the httpserver class, inside the com.sun.net package. I'm relatively new to Java, so I thought that a class "sponsored" by Oracle itself would be included in the default libraries.
Unfortunately, that was not the case. After a lot of trials for possible syntax-import errors (various kinds of error arouse) and having installed the Oracle JDK 8 correctly on my Ubuntu machine, the compiler said that the package did not exist. What do I have to do to get the package to work?
I did finally make it work. Mostly, it was a misunderstanding from my place, since I only imported up to a point that was wrong - that is,I only imported com.sun.net.httpserver, thinking the latter part was the actual class I wanted, but it was merely the package name. So then I proceeded to import com.sun.net.httpserver.HttpServer, then the rest of my classes. Finally a com.sun.net.httpserver.* would work perfectly fine. It seems stupid now that I figured it out, but I think I will leave it here just in case anyone has the same misunderstanding - I already see 1 favourite on the question. And of course, as others have pointed out, the package is not part of the standard java libraries, but I used Oracle Java specifically for that.
P.S. The class is really useful, unlike what the other answer implies, but now I have stumbled upon another problem regarding reading the request body right, something that might have to do with the locale of the client-server, and I will now procced to search that.. Just a warning for anyone thinking of using the package.
Firstly try to avoid com.sun.xxx package, as those are internalls of Oracle/Sun java implementation.
Secondly, why not use libraries from apache ? See https://hc.apache.org/
EDITED:
You can also look on http://sparkjava.com/ , not tested but examples looks promising and they are using Java 8 nice features.
I'm enhancing a client, which is part of a bigger project. Because of the lack of speed i was forced to switch to CNI and therefore i had to generate native code with the GNU-gcj compiler (gnu 4.6.3).
The compiling and linking works fine (thanks to the -findirect-dispatch flag) and i don't have any problems executing the output.
But when it comes to the communication between the client and the server, the client immediately disconnects. The reason:
[XStreamClient Reader] WARN - Client disconnected (Exception:
com.thoughtworks.xstream.io.StreamException: Cannot create
XmlPullParser)
(This Exeption only appears in the gcj compiled version of the client. When i run the code with the java interpreter - things work well (but too slow^^))
--> The challenging part is that i can't retrieve the source code of where this exception occurs because it is in a pre-compiled (Java class files) library the client uses. (And I cannot contact the author of that library)
I guess the library invokes the XppReader which then tries to create a XmlPullParser class and fails.
I bind in the XStream (vers. 1.4.3) library (and other required *.jars) by unpacking them and compiling the created *.class files and then linking the object files. This seems to work for all other librarys, too. (My OS=Ubuntu)
What i already did to overcome this problem:
I googled intensively for XStream/XmlPullParser and gcj and replaced the "xmlpull"- and "kxml2"-files with different versions.
But nothing worked.
Does anyone of you have a clue of what might be the solution?
EDIT:
I figured out that the reason why the XmlPullParser creation fails is that the META-INF directory with the /services/org.xmlpull.v1.XmlPullParserFactory file can not be found by the XmlPullParserFactory.newInstance function.
This is due to the fact that i only compiled and linked the *.jar's *.class files.
So as soon as i found i way to link the META-INF directory into the executable in away that the function can find and access it, the problem should be solved.
Does anyone of you already know a way to do so?
I think xmlpull need an implementation which can use xpp3 as its implementation.
Please add following code into your pom.xml and if required, add these jar files to the software which requires them.
<dependency>
<groupId>xmlpull</groupId>
<artifactId>xmlpull</artifactId>
<version>1.1.3.1</version>
</dependency>
<dependency>
<groupId>xpp3</groupId>
<artifactId>xpp3</artifactId>
<version>1.1.3.3</version>
</dependency>
I think that you've made a couple of mistakes in your implementation platform choices:
You probably didn't need to go to the lengths of implementing stuff in native code "for speed". For most things you can get roughly comparable speed in Jana as in native code, especially if you take the time to profile and optimize your Java code.
Assuming that you did, CNI was a poor choice. You would have been better off using JNI or JNA, both of which allow you to use Oracle HotSpot / OpenJDK releases.
GCJ is a poor choice because (as you have observed) some things don't work, and debugging is more difficult. (See also Is GNU's Java Compiler (GCJ) dead?)
Relying on a library that you cannot get source code for is unfortunate.
My advice would be to revisit as many of those "missteps" as possible.
As i already edited into my question, the reason why the creation fails is that the XmlPullParserFactory.newInstance method is not able to access the /META-INF/services/org.xmlpull.v1.XmlPullParserFactory file by using the following line of code:
InputStream is = context.getResourceAsStream (RESOURCE_NAME);
(RESOURCE_NAME equals "/META-INF/services/org.xmlpull.v1.XmlPullParserFactory")
I must admit that i didn't find a way to bind in the needed META-INF directory into the executable, which would have been one of the most elegant solutions.
But since the XmlPullParserFactory.java file (and XStream library) is open source you just need do add one line of code into above's source file and replace the old class, with the new one - and that's it.
In the public static XmlPullParserFactory newInstance (String classNames, Class context) function the program only wants to read from the RESOURCE_NAME file when classNames == null.
So what we do to avoid this is to assign the RESOURCE_NAME's file content to the classNames variable by our selves and for that place this line of code above the if (classNames == null || classNames.length() == 0 || "DEFAULT".equals(classNames)) statement:
classNames = "org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer";
"org.xmlpull.mxp1.MXParser,org.xmlpull.mxp1_serializer.MXSerializer" is my RESOURCE_NAME-file's content. If the content of your file differs from mine -> put in yours instead.
Best regards, Chris
I have a project which depends on several 3rd party libraries, the project itself is packaged as a jar and distributed to other developers as a library.
Those developers add the dependencies to their classpath and use my library in their code.
Recently I had an issue with one of the 3rd party dependencies, the apache commons codec libary,
The problem is this:
byte[] arr = "hi".getBytes();
// Codec Version 1.4
Base64.encodeBase64String(arr) == "aGk=\r\n" // this is true
// Codec Version 1.6
Base64.encodeBase64String(arr) == "aGk=" // this is true
As you can see the output of the method has changed with the minor version bump.
My question is, I don't want to force the user of my library to a specific minor version of a 3rd party library. Assuming I know about the change to the dependent library, is there anyway in which I can recognize which library version is being included in the classpath and behave accordingly? or alternatively, what is considered to be the best practice for these kind of scenarios?
P.S - I know that for the above example I can just use new String(Base64.encodeBase64(data, false)) which is backwards compatible, this is a more general question.
You ask what is the "best practice" for this problem. I'm going to assume that by "this problem" you mean the problem of 3rd party library upgrades, and specifically, these two questions:
When should you upgrade?
What should you do to protect yourself against bad upgrades (like the commons-codec bug mentioned in your example)?
To answer the first question, "when should you upgrade?," many strategies exist in industry. In the majority of the commercial Java world I believe the current dominant practice is "you should upgrade when you are ready to." In other words, as the developer, you first need to realize that a new version of a library is available (for each of your libraries!), you then need to integrate it into your project, and you are the one who makes the final go/no-go decision based on your own test bed --- junit, regression, manual testing, etc... whatever it is you do to ensure quality. Maven facilitates this approach (I call it version "pinning") by making multiple versions of most popular libraries available for automatic download into your build system, and by tacitly fostering this "pinning" tradition.
But other practices do exist, for example, within the Debian Linux distribution it is theoretically possible to delegate a lot of this work to the Debian package maintainers. You would simply dial in your comfort level according to the 4 levels Debian makes available, choosing newness over risk, or vice versa. The 4 levels Debian makes available are: OLDSTABLE, STABLE, TESTING, UNSTABLE. Unstable is remarkably stable, despite its name, and OLDSTABLE offers libraries that may as much as 3 years out of date compared to the latest-and-greatest versions available on their original "upstream" project websites.
As for the 2nd question, how to protect yourself, I think the current 'best practice' in industry is twofold: choose your libraries based on reputation (Apache's is generally pretty good), and wait a little while before upgrading, e.g., don't always rush to be on the latest-and-greatest. Maybe choose a public release of the library that has already been available 3 to 6 months, in the hope that any critical bugs have been flushed out and patched since the initial release.
You could go farther, by writing JUnit tests that specifically protect the behaviours you rely on in your dependencies. That way, when you bring down the newer version of a library, your JUnit would fail right away, warning you of the problem. But I don't see a lot of people doing that, in my experience. And it's often difficult to be aware of the precise behaviour you are relying on.
And, by the way, I'm Julius, the guy responsible for this bug! Please accept my apologies for this problem. Here's why I think it happened. I will speak only for myself. To find out what others on the apache commons-codec team think, you'll have to ask them yourself (e.g., ggregory, sebb).
When I was working on Base64 in versions 1.4 and 1.5, I was very much focused on the main problem of Base64, that is, encoding binary data into the lower-127 ASCIi, and the decoding it back to binary.
So in my mind (and here's where I went wrong) the difference between "aGk=\r\n" and "aGk=" is immaterial. They both decode to the same binary result!
But thinking about it in a broader sense after reading your stackoverflow posting here, I realize there is probably a very popular usecase that I never considered. That is, password checking against a table of encrypted passwords in a database. In that usecase you probably do the following:
// a. store user's password in the database
// using encryption and salt, and finally,
// commons-codec-1.4.jar (with "\r\n").
//
// b. every time the user logs in, encrypt their
// password using appropriate encryption alg., plus salt,
// finally base64 encode using latest version of commons-codec.jar,
// and then check against encrypted password in the database
// to see if it matches.
So of course this usecase fails if commons-codec.jar changes its encoding behaviour, even in immaterial ways according to the base64 spec. I'm very sorry!
I think even with all of the "best-practices" I spelled out at the beginning of this post, there's still a high probability of getting screwed on this one. Debian Testing already contains commons-codec-1.5, the version with the bug, and to fix this bug essentially means screwing people who used version 1.5 instead of version 1.4 where you did. But I will try to put some documentation on the apache website to warn people. Thanks for mentioning it here on stack-overflow (am I right about the usecase?).
ps. I thought Paul Grime's solution was pretty neat, but I suspect it relies on projects pushing version info in the the Jar's META-INF/MANIFEST.MF file. I think all Apache Java libraries do this, but other projects might not. The approach is a nice way to pin yourself to versions at build-time though: instead of realizing that you depend on the "\r\n", and writing the JUnit that protects against that, you can instead write a much easier JUnit: assertTrue(desiredLibVersion.equals(actualLibVersion)).
(This assumes run-time libs don't change compared to build-time libs!)
package stackoverflow;
import org.apache.commons.codec.binary.Base64;
public class CodecTest {
public static void main(String[] args) {
byte[] arr = "hi".getBytes();
String s = Base64.encodeBase64String(arr);
System.out.println("'" + s + "'");
Package package_ = Package.getPackage("org.apache.commons.codec.binary");
System.out.println(package_);
System.out.println("specificationVersion: " + package_.getSpecificationVersion());
System.out.println("implementationVersion: " + package_.getImplementationVersion());
}
}
Produces (for v1.6):
'aGk='
package org.apache.commons.codec.binary, Commons Codec, version 1.6
specificationVersion: 1.6
implementationVersion: 1.6
Produces (for v1.4):
'aGk=
'
package org.apache.commons.codec.binary, Commons Codec, version 1.4
specificationVersion: 1.4
implementationVersion: 1.4
So you could use the package object to test.
But I would say that it's a bit naughty for the API to have changed the way it did.
EDIT Here is the reason for the change - https://issues.apache.org/jira/browse/CODEC-99.
You could calculate a md5 sum of the actual class file and compare it to the expected. Could work like this:
String classname = "java.util.Random"; //fill in the your class
MessageDigest digest = MessageDigest.getInstance("MD5");
Class test = Class.forName(classname);
InputStream in = test.getResourceAsStream("/" + classname.replace(".", "/") + ".class");
byte[] buffer = new byte[8192];
int read = 0;
while ((read = in.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
byte[] md5sum = digest.digest();
BigInteger bigInt = new BigInteger(1, md5sum);
String output = bigInt.toString(16);
System.out.println(output);
in.close();
Or maybe you could iterate over the filenames in the classpath. Of course this only works, if the devs use the original filenames.
String classpath = System.getProperty("java.class.path");
for(String path:classpath.split(";")){
File o = new File(path);
if(o.isDirectory()){
....
}
}
Asaf, I solve this problem by using Maven . Maven has nice versioning support for all artifacts you use in your project. On top of that, I use the excellent Maven Shade Plugin which gives you ability to package all 3rd party libraries (maven artifacts) in a single JAR file, ready for deployment. All other solutions are just inferior - I am talking from my personal experience - I've been there, done that... Even wrote my own plugin-manager, etc. Use Maven, that is my friendly advice.
replacing the newline with empty string could be a solution?
Base64.encodeBase64String(arr).replace("\r\n","");
I would create 2+ different versions of a library to complement appropriate third party library version and provide manual which one to use. Probably write correct pom for it.
To resolve your problem I think the best way is to use a OSGi container, so you can choose your version of the 3rd party dependency and other libraries can safely use the other version without any conflict.
If you cannot rely on a OSGi container then you can use the implementation version in the MANIFEST.MF
Maven is a great tool, but cannot alone resolve your problem.
Of course the CLASSPATH form (non underscore version) is what people use now.
But I thought it used to also accept CLASS_PATH, maybe way back in the early 2000's?
I've Google'd around but haven't seen this answered. Google has trouble with this type of search, given the abundance of classpath, class and path in relation to Java. There are some older posts showing it as CLASS_PATH, and the one person who actually asked about the two versions didn't get a real answer on that board.
I was also wondering if maybe it was specific to one old JVM variant, or maybe to an early DOS / Windows port?
Obviously not a high priority, but was curious if anybody else remembered this, and whether there was ever any "official" support (or withdrawal) for it.
Thanks, Mark
You got me curious too - I found one reference googling "CLASS_PATH Gosling", the java faq in version 0.9.7. I can faintly remember (or I´m imagining) using it...
http://journals.ecs.soton.ac.uk/java/javafaq.html#xtocid558364
Searching on Google with quotes around CLASS_PATH ("CLASS_PATH") will certainly help your searches for this. That said, I've never seen this - except in some batch files used to start programs which passed this to java's command line argument.