Java 8 os.version does not contain entire Windows version - java

For Windows 10, Java 8 returns os.version=10.0 from System Properties, while the Windows 'ver' command returns 10.0.14393.
Is there any way to get the full windows version from java without running an external command?
Why is Java truncating the Windows version?

The answer is, as ever, in the code - it's not that it's truncating it; it just never populates the build number.
Looking at the jdk8 source, they only populated dwMajorVersion and dwMinorVersion:
sprintf(buf, "%d.%d", ver.dwMajorVersion, ver.dwMinorVersion);
sprops.os_version = _strdup(buf);
It's been this way since at least the jdk6.
Now, if you want to get a full windows version, including the build, then you can use JNA - the classes/interfaces you're looking for is com.sun.jna.platform.win32.WinNT, which contains the VERSIONINFOEX structure, and com.sun.jna.platform.win32.Kernel32 for the GetVersionEx function. I don't have a copy of windows to stub out the code for you; but it should be relatively easy to do (maybe something like this? I can't even try to test this out):
import com.sun.jna.platform.win32.*;
import java.text.MessageFormat;
public static void main(String args[]) {
Kernel32 kernel = Kernel32.INSTANCE;
WinNT.OSVERSIONINFOEX vex = new WinNT.OSVERSIONINFOEX();
if (kernel.GetVersionEx(vex)) {
System.out.println(MessageFormat.format("{0}.{1}.{2}",
vex.dwMajorVersion.toString(),
vex.dwMinorVersion.toString(),
vex.dwBuildNumber.toString()));
}
}
Asking for a rationale for this; it's pretty simple really - it never really mattered before windows 10 - you had strong delineations of behaviour based on the major and minor version of the OS; with the introduction of features by build for windows 10 it's complicated things.

Related

InternetDomainName and publicsuffix list

Which version of public suffix list(https://publicsuffix.org/) does Guava 21 InternetDomainName API use?
Parsing keyupgrade.spaceforupdate.download results in
scala> InternetDomainName.from("keyupgrade.spaceforupdate.download").topPrivateDomain
java.lang.IllegalStateException: Not under a public suffix: keyupgrade.spaceforupdate.download
at com.google.common.base.Preconditions.checkState(Preconditions.java:176)
at com.google.common.net.InternetDomainName.topPrivateDomain(InternetDomainName.java:445)
... 50 elided
But .download is a valid public suffix as per https://publicsuffix.org/list/public_suffix_list.dat.
I am thinking Guava 21 is using an older version of publicsuffix list. Is there a way to update it? Thanks!
I'm pretty sure you have a Guava v14 jar on your classpath, possibly in addition to the v21 jar you think you're using. It was released in 2013, before .download was apparently added as a TLD.
Looking at your stack trace, it indicates the exception was thrown from line 176 of Preconditions.java, but in v21 that line is just a */. Stepping backwards it's not until v17 that the line number makes any sense.
Same problem with InternetDomainName - compare v21 vs. v14 (Preconditions also lines up in v14).
So take a closer look at your classpath, I think that's your problem.
Edit: Confirmed this works in v21 with Scala:
$ scala -cp guava-21.0.jar
Welcome to Scala 2.11.11 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> import com.google.common.net._
import com.google.common.net._
scala> InternetDomainName.from("keyupgrade.spaceforupdate.download").topPrivateDomain
res0: com.google.common.net.InternetDomainName = spaceforupdate.download
This conversation was happening in parallel on the guava mailing list and here; I will consolidate it here. In the most recent reply on the mailing list, Neera responded to my request for example code with the following:
I am trying to parse "keyupgrade.spaceforupdate.download" where
.download is a valid TLD as per the latest mozilla public suffix
list, but Guava fails to parse it.
scala>
InternetDomainName.from("keyupgrade.spaceforupdate.download").topPrivateDomain
java.lang.IllegalStateException: Not under a public suffix:
keyupgrade.spaceforupdate.download at
com.google.common.base.Preconditions.checkState(Preconditions.java:176)
at
com.google.common.net.InternetDomainName.topPrivateDomain(InternetDomainName.java:445)
... 50 elided
I'm wondering if this might be a Scala-specific issue. As I mentioned, 'download' has been in the PSL for a long time (since 2014-11-20 according to the PSL itself), and it's in the local copies of the PSL used to build Guava for years before version 21 was built. Note that I tested this in Java against our head version, and got the expected output, "spaceforupdate.download":
public static void main(String[] args) {
InternetDomainName top =
InternetDomainName.from("keyupgrade.spaceforupdate.download").topPrivateDomain();
System.out.println(top);
}
Do tests with "obvious" suffixes work? E.g., the top private domain of "www.google.com" should be "google.com". Please try that, and also, if possible, try a test in Java rather than Scala. I'll look forward to hearing how those tests go.
I'm the principle maintainer of InternetDomainName. Sorry you're having problems with it.
It appears that the version of the PSL incorporated into Guava 21 was obtained from Mozilla on 2016-11-30. Unfortunately, there's no straightforward way to update it yourself.
That being said, I just looked back through older versions of the PSL, and "download" has been in there for a long time, well before the version used in Guava 21. Would you mind posting some working example code that demonstrates the problem you're seeing?

Java code in different build environments [duplicate]

My project requires Java 1.6 for compilation and running. Now I have a requirement to make it working with Java 1.5 (from the marketing side). I want to replace method body (return type and arguments remain the same) to make it compiling with Java 1.5 without errors.
Details: I have an utility class called OS which encapsulates all OS-specific things. It has a method
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using java.awt.Desktop
...
}
to open files like with double-click (start Windows command or open Mac OS X command equivalent). Since it cannot be compiled with Java 1.5, I want to exclude it during compilation and replace by another method which calls run32dll for Windows or open for Mac OS X using Runtime.exec.
Question: How can I do that? Can annotations help here?
Note: I use ant, and I can make two java files OS4J5.java and OS4J6.java which will contain the OS class with the desired code for Java 1.5 and 1.6 and copy one of them to OS.java before compiling (or an ugly way - replace the content of OS.java conditionally depending on java version) but I don't want to do that, if there is another way.
Elaborating more: in C I could use ifdef, ifndef, in Python there is no compilation and I could check a feature using hasattr or something else, in Common Lisp I could use #+feature. Is there something similar for Java?
Found this post but it doesn't seem to be helpful.
Any help is greatly appreciated. kh.
Nope there isn't any support for conditional compilation in Java.
The usual plan is to hide the OS specific bits of your app behind an Interface and then detect the OS type at runtime and load the implementation using Class.forName(String).
In your case there no reason why you can't compile the both OS* (and infact your whole app) using Java 1.6 with -source 1.5 -target 1.5 then in a the factory method for getting hold of OS classes (which would now be an interface) detect that java.awt.Desktop
class is available and load the correct version.
Something like:
public interface OS {
void openFile(java.io.File file) throws java.io.IOException;
}
public class OSFactory {
public static OS create(){
try{
Class.forName("java.awt.Desktop");
return new OSJ6();
}catch(Exception e){
//fall back
return new OSJ5();
}
}
}
Hiding two implementation classes behind an interface like Gareth proposed is probably the best way to go.
That said, you can introduce a kind of conditional compilation using the replace task in ant build scripts. The trick is to use comments in your code which are opened/closed by a textual replacement just before compiling the source, like:
/*{{ Block visible when compiling for Java 6: IFDEF6
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using java.awt.Desktop
...
/*}} end of Java 6 code. */
/*{{ Block visible when compiling for Java 5: IFDEF5
// open the file using alternative methods
...
/*}} end of Java 5 code. */
now in ant, when you compile for Java 6, replace "IFDEF6" with "*/", giving:
/*{{ Block visible when compiling for Java 6: */
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using java.awt.Desktop
...
/*}} end of Java 6 code. */
/*{{ Block visible when compiling for Java 5, IFDEF5
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using alternative methods
...
/*}} end of Java 5 code. */
and when compiling for Java 5, replace "IFDEF5". Note that you need to be careful to use // comments inside the /*{{, /*}} blocks.
You can make the calls using reflection and compile the code with Java 5.
e.g.
Class clazz = Class.forName("java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);
You can catch any exceptions and fall back to something which works on Java 5.
The Ant script introduced below gives nice and clean trick.
link: https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html
in example,
//[ifdef]
public byte[] getBytes(String parameterName)
throws SQLException {
...
}
//[enddef]
with Ant script
<filterset begintoken="//[" endtoken="]">
<filter token="ifdef" value="${ifdef.token}"/>
<filter token="enddef" value="${enddef.token}"/>
</filterset>
please go to link above for more detail.
In java 9 it's possible to create multi-release jar files. Essentially it means that you make multiple versions of the same java file.
When you compile them, you compile each version of the java file with the required jdk version. Next you need to pack them in a structure that looks like this:
+ com
+ mypackage
+ Main.class
+ Utils.class
+ META-INF
+ versions
+ 9
+ com
+ mypackage
+ Utils.class
In the example above, the main part of the code is compiled in java 8, but for java 9 there is an additional (but different) version of the Utils class.
When you run this code on the java 8 JVM it won't even check for classes in the META-INF folder. But in java 9 it will, and will find and use the more recent version of the class.
I'm not such a great Java expert, but it seems that conditional compilation in Java is supported and easy to do. Please read:
http://www.javapractices.com/topic/TopicAction.do?Id=64
Quoting the gist:
The conditional compilation practice is used to optionally remove chunks of code from the compiled version of a class. It uses the fact that compilers will ignore any unreachable branches of code.
To implement conditional compilation,
define a static final boolean value as a non-private member of some class
place code which is to be conditionally compiled in an if block which evaluates the boolean
set the value of the boolean to false to cause the compiler to ignore the if block; otherwise, keep its value as true
Of course this lets us to "compile out" chunks of code inside any method. To remove class members, methods or even entire classes (maybe leaving only a stub) you would still need a pre-processor.
if you don't want conditionally enabled code blocks in your application then a preprocessor is only way, you could take a look at java-comment-preprocessor which can be used for both maven and ant projects
p.s.
also I have made some example how to use preprocessing with Maven to build JEP-238 multi-version JAR without duplication of sources
Java Primitive Specializations Generator supports conditional compilation:
/* if Windows compilingFor */
start();
/* elif Mac compilingFor */
open();
/* endif */
This tool has Maven and Gradle plugins.
hi I have got similar problem when I have shared library between Java SDK abd Android and in both environments are used the graphics so basically my code must to work with both
java.awt.Graphics and android.graphics.Canvas,
but I don't want to duplicate almost any code.
My solution is to use wrapper, so I access to graphisc API indirectl way, and
I can change a couple of imports, to import the wrapper I want to compile the projects.
The projects have some cone shaded and some are separate, but there is no duplicating anything except of couple of wrappers etc.
I think it is the best what I can do.

how windows will do auto java update checks?

First of all sorry for my poor English.
I want to know how the windows will do auto java update check behind the User Interface ?
The UI will just react based on our input which is in the link , http://java.com/en/download/help/java_update.xml#howto .
But , how windows checks the updates programmatically.
I wrote a small program in java ,
public class JavaLatestVersion {
public static void main(String[] args){
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new URL(
"http://java.com/applet/JreCurrentVersion2.txt").openStream())) ;
String fullVersion = br.readLine();
System.out.println("fullVersion : "+fullVersion);
String version = fullVersion.split("_")[0];
String revision = fullVersion.split("_")[1];
System.out.println("Version " + version + " revision " + revision);
} catch (IOException e) {
e.printStackTrace();
}
}
}
My questions :
1. Is the above program is the reliable way to get the latest java version ? Or any other standard way to get the latest java version (Not in the computer) ?
2. Is windows use the same way to determine the latest java version ?
3. Is windows use this link for updates http://java.com/applet/JreCurrentVersion2.txt ?
Any one know the secret code behind how windows will check for latest java updates?
Thanks in advance.
Checking for Java updates is done by Java Auto Updater. It is ordinary application (which is ran when Windows starts up).
Yes, it is reliable way to get the latest version of Java (as updater can not only update Java, it can also update itself). But pay attention to firewall/group policy settings which can prohibit updater to access the Web.
Windows doesn't update Java.
Only debugging Java Auto Updater can help to determine what URL it uses.
Unfortunately, Java Auto Updater has only graphical interface and hides all work behind the scenes. So finding a "secret code" is not easy to do. All the more in many cases reverse-engineering non-open source software is illegal from a license point of view.
URL that you provided above doesn't works. Because it says 8.0_51. But latest version of Java on Downloads page is 8u65 / 8u66.
Seems that latest available version (as plain text) can be determined only by fetching http://www.oracle.com/technetwork/java/javase/downloads/index.html web page, then parsing it, handling cases when page is moved to another location, etc.

Using Inline::Java in perl with threads

I am writing a trading program in perl with the newest Finance::InteractiveBrokers::TWS
module. I kick off a command line interface in a separate thread at the
beginning of my program but then when I try to create a tws object, my program
exits with this message:
As of Inline v0.30, use of the Inline::Config module is no longer supported or
allowed. If Inline::Config exists on your system, it can be removed. See the
Inline documentation for information on how to configure Inline. (You should
find it much more straightforward than Inline::Config :-)
I have the newest versions of Inline and Inline::Java. I looked at TWS.pm and it doesn't seem to be using Inline::Config. I set 'SHARED_JVM => 1' in the 'use Inline()' and 'Inline->bind()' calls in TWS.pm but that did not resolve the issue...
My Code:
use Finance::InteractiveBrokers::TWS;
use threads;
use threads::shared;
our $callback;
our $tws;
my $interface = UserInterface->new();
share($interface);
my $t = threads->create(sub{$interface->runUI()});
$callback= TWScallback->new();
$tws = Finance::InteractiveBrokers::TWS->new($manager); #This is where the program fails
So is Inline::Config installed on your system or not? A cursory inspection of the code is not sufficient to tell whether Perl is loading a module or not. There are too many esoteric ways (some intentional and some otherwise) to load a package or otherwise populate a namespace.
The error message in question comes from this line of code in Inline.pm:
croak M14_usage_Config() if %main::Inline::Config::;
so something in your program is populating the Inline::Config namespace. You should do what the program instructs you to do: find out where Inline/Config.pm is installed on your system (somewhere in your #INC path) and delete it.

Pinning a Java application to the Windows 7 taskbar

I use Launch4j as a wrapper for my Java application under Windows 7, which, to my understanding, in essence forks an instance of javaw.exe that in turn interprets the Java code. As a result, when attempting to pin my application to the task bar, Windows instead pins javaw.exe. Without the required command line, my application will then not run.
As you can see, Windows also does not realize that Java is the host application: the application itself is described as "Java(TM) Platform SE binary".
I have tried altering the registry key HKEY_CLASSES_ROOT\Applications\javaw.exe to add the value IsHostApp. This alters the behavior by disabling pinning of my application altogether; clearly not what I want.
After reading about how Windows interprets instances of a single application (and a phenomenon discussed in this question), I became interested in embedding a Application User Model ID (AppUserModelID) into my Java application.
I believe that I can resolve this by passing a unique AppUserModelID to Windows. There is a shell32 method for this, SetCurrentProcessExplicitAppUserModelID. Following Gregory Pakosz suggestion, I implemented it in an attempt to have my application recognized as a separate instance of javaw.exe:
NativeLibrary lib;
try {
lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
Logger.out.error("Could not load Shell32 library.");
return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
Function function = lib.getFunction(functionName);
int ret = function.invokeInt(args);
if (ret != 0) {
Logger.out.error(function.getName() + " returned error code "
+ ret + ".");
}
} catch (UnsatisfiedLinkError e) {
Logger.out.error(functionName + " was not found in "
+ lib.getFile().getName() + ".");
// Function not supported
}
This appears to have no effect, but the function returns without error. Diagnosing why is something of a mystery to me. Any suggestions?
Working implementation
The final implementation that worked is the answer to my follow-up question concerning how to pass the AppID using JNA.
I had awarded the bounty to Gregory Pakosz' brilliant answer for JNI that set me on the right track.
For reference, I believe using this technique opens the possibility of using any of the APIs discussed in this article in a Java application.
I don't have Windows 7 but here is something that might get you started:
On the Java side:
package com.stackoverflow.homework;
public class MyApplication
{
static native boolean setAppUserModelID();
static
{
System.loadLibrary("MyApplicationJNI");
setAppUserModelID();
}
}
And on the native side, in the source code of the `MyApplicationJNI.dll library:
JNIEXPORT jboolean JNICALL Java_com_stackoverflow_homework_MyApplication_setAppUserModelID(JNIEnv* env)
{
LPCWSTR id = L"com.stackoverflow.homework.MyApplication";
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(id);
return hr == S_OK;
}
Your question explicitly asked for a JNI solution. However, since your application doesn't need any other native method, jna is another solution which will save you from writing native code just for the sake of forwarding to the windows api. If you decide to go jna, pay attention to the fact that SetCurrentProcessExplicitAppUserModelID() is expecting a UTF-16 string.
When it works in your sandbox, the next step is to add operating system detection in your application as SetCurrentProcessExplicitAppUserModelID() is obviously only available in Windows 7:
you may do that from the Java side by checking that System.getProperty("os.name"); returns "Windows 7".
if you build from the little JNI snippet I gave, you can enhance it by dynamically loading the shell32.dll library using LoadLibrary then getting back the SetCurrentProcessExplicitAppUserModelID function pointer using GetProcAddress. If GetProcAddress returns NULL, it means the symbol is not present in shell32 hence it's not Windows 7.
EDIT: JNA Solution.
References:
The JNI book for more JNI examples
Java Native Access (JNA)
There is a Java library providing the new Windows 7 features for Java. It's called J7Goodies by Strix Code. Applications using it can be properly pinned to the Windows 7 taskbar. You can also create your own jump lists, etc.
I have implemented access to the SetCurrentProcessExplicitAppUserModelID method using JNA and it works quite well when used as the MSDN documentation suggests. I've never used the JNA api in the way you have in your code snippet. My implementation follows the typical JNA usage instead.
First the Shell32 interface definition:
interface Shell32 extends StdCallLibrary {
int SetCurrentProcessExplicitAppUserModelID( WString appID );
}
Then using JNA to load Shell32 and call the function:
final Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
{
put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
}
};
Shell32 shell32 = (Shell32) Native.loadLibrary("shell32", Shell32.class,
WIN32API_OPTIONS);
WString wAppId = new WString( "Vendor.MyJavaApplication" );
shell32.SetCurrentProcessExplicitAppUserModelID( wAppId );
Many of the API's in the last article you mentioned make use of Windows COM which is quite difficult to use directly with JNA. I have had some success creating a custom DLL to call these API's (eg. using the SHGetPropertyStoreForWindow to set a different app ID for a submodule window) which I then use JNA to access at runtime.
Try to use JSmooth. I use always this one. In JSmooth is there an option under Skeleton by Windowed Wrapper called
Lauch java app in exe process
See on this image.
(source: andrels.com)
Also command line arguments can be passed.
I think this can be a solution for you.
Martijn
SetCurrentProcessExplicitAppUserModelID (or SetAppID()) would in fact do what you're trying to do. However, it might be easier to modify your installer to set the AppUserModel.ID property on your shortcut - quoting from the Application User Model ID document mentioned above:
In the System.AppUserModel.ID property of the application's shortcut file. A shortcut (as an IShellLink, CLSID_ShellLink, or a .lnk file) supports properties through IPropertyStore and other property-setting mechanisms used throughout the Shell. This allows the taskbar to identify the proper shortcut to pin and ensures that windows belonging to the process are appropriately associated with that taskbar button.
Note: The System.AppUserModel.ID property should be applied to a shortcut when that shortcut is created. When using the Microsoft Windows Installer (MSI) to install the application, the MsiShortcutProperty table allows the AppUserModelID to be applied to the shortcut when it is created during installation.
The latest jna-platform library now includes JNA bindings for SetCurrentProcessExplicitAppUserModelID:
https://github.com/java-native-access/jna/pull/680
I fixed mine without any ID settings.
There is an option in Launch4J if you are using it and you say you do then...
You can change the header to JNI Gui and then wrap it around the jar with the JRE.
The good thing is that it runs .exe in the process now instead on running javaw.exe with your jar. It probably does it under the hood (not sure).
Also I have noticed also that it takes around 40-50% less CPU resource which is even better!
And the pinning works fine and all that window features are enabled.
I hope it helps to someone as I spent nearly 2 days trying to solve that issue with my undecorated javafx app.

Categories