Il aurait fallu beaucoup de temps pour écrire les détails de l'affaire, alors j'écrirai d'abord la conclusion.
Dans la version java" 1.8.0_92 "
, des correctifs ont été ajoutés à Nashorn, ce qui peut changer le comportement de JavaScript fonctionnant sur Nashorn en mettant à jour Java. Les changements qui semblent avoir le plus d'impact (et je suis vraiment dedans) sont:
*** Lorsque le type long Java et le type int sont passés à JavaScript exécuté par Nashorn, ils étaient traités comme du type Number
dans le passé, mais après modification, ils sont traités comme du type ʻObject` ***
Il y a probablement des modèles dans le code qui sont affectés par ce changement (changements de comportement), mais une comparaison typique (en fait je suis accro) fait des comparaisons d'égalité strictes. Je vais.
// JavaScript
function hoge(arg) { // <-arg est un objet qui stocke les arguments passés de Java
if arg.getLongValue() === 0 return 0 // <-Ici arg.getLongValue()Est 0L sur Java===Le résultat de est faux et else est exécuté
else arg.getLongValue / 2;
};
Il existe deux contre-mesures possibles pour les cas ci-dessus.
===
) et passez à la comparaison d'égalité (==
) pour la partie où la valeur numérique (long, int) transmise depuis Java et le type JS Number sont comparées. ..Celui qui doit être adopté dépend de la situation, mais si vous voulez modifier le côté Java, vous devez construire, déployer et redémarrer, donc dans de nombreux cas, je pense que 1. est plus facile.
Un moteur JavaScript pour exécuter JavaScript en Java.
Dans «Java SE 6-7», il y avait un moteur JavaScript Mozilla appelé «Rhino», mais dans «Java SE 8», il a été remplacé par «Nashorn» d'Oracle. Comparé à Rhino
, il est compatible avec ʻECMAScript-262`, et la vitesse d'exécution est grandement améliorée, ce qui semble être une grande différence.
Je pense qu'il existe de nombreuses utilisations de Nashorn, mais par exemple, il est nécessaire d'activer le «remplacement dynamique de la logique». Dans un certain processus de calcul, j'aimerais faire quelque chose comme un test AB de logique pour voir quel type de changement se produira dans les performances, et si un changement positif est observé, passer progressivement à une nouvelle logique. Je vois.
Je pense que l'explication est abstraite et difficile à comprendre, mais en bref
// Java
Object a: = doSomething() // step 1
Object b = executeDynamicLogic(a) // step 2 <--Je veux le remplacer facilement!
return b // step 3
L'ambiance est comme ça.
Dans l'exemple ci-dessus, passez l'argument «a» au code de script extrait de la base de données, etc. et exécutez-le, et stockez le résultat dans la variable «b». .. .. Je veux pouvoir changer le comportement de l'application simplement en METTRE À JOUR le script stocké dans la base de données. C'est comme traiter la logique comme des données.
Si vous pouvez atteindre l'objectif, vous pouvez utiliser Python ou Ruby au lieu de JavaScript, mais dans mon cas,
Java SE
D'un tel point de vue, je me souviens que j'ai décidé d'utiliser JavaScript.
À un moment donné, JavaScript fonctionnant sur Nashorn, qui n'avait jamais eu de problème auparavant, a commencé à donner une erreur.
Quand j'ai commencé à enquêter, j'ai naturellement suspecté des changements dans mon code, mais je n'ai fait aucun changement autour de Nashorn et le script en cours d'exécution a également été transmis au script. Il n'y avait rien de suspect dans les données. Quand j'ai commencé à penser que je ne comprenais pas cela ...
** "Oh, peut-être que j'ai mis à jour la version Java ..." **
Un rayon de lumière. À ce stade, j'ai commencé à douter de la possibilité que "Nashorn ne soit pas affecté par certains changements dans la mise à jour?", Et quand je l'ai recherché, je l'ai trouvé très rapidement.
JDK-8144020 | Remove long as an internal numeric type
En résumé,
*** Jusqu'à présent, «int» et «long» étaient également traités en interne comme «double» et mappés sur «nombre» JS (en Java, la définition de «nombre» de type ECMA est satisfaite. (Parce qu'il n'est que «double») Cependant, lorsque vous traitez «long» comme «double», certains problèmes surviennent en raison de l'ajout d'une précision supplémentaire de 53 bits, alors arrêtez ce processus de conversion interne YO! *** ***
.. .. .. Vraiment? Donc, quand je vérifie l'environnement d'exploitation
$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
Hmmm. Il est supérieur à "1.8.0_92". .. ..
Le code à l'origine du problème ressemblait à ceci:
// JavaScript
function hoge(arg) { // <-arg est un objet qui stocke les arguments passés de Java
if arg.getLongValue1() === 0 return 0
else arg.getValue1() / arg.getLongValue2();
};
Le fait est que nous essayons d'éviter la division zéro, mais le problème est
arg.getValue1() === 0
C'est la partie de. Comparaison d'égalité exacte (vérifiez si les types et les valeurs correspondent) entre ʻarg.getValue1 () , qui est le type
long dans le monde Java, et
0, qui est le type
Number` dans le monde JS. )Faire.
Pour Nashorn jusqu'à Java8u91
, si ʻarg.getValue1 () == 0L est
true du côté Java, cette expression renvoie
true. Cependant, depuis «Java8u92», le résultat est «faux». La raison en est que les valeurs des côtés gauche et droit de **
===sont
0`, mais les types sont différents **.
//Arg du côté Java.getValue1()Si est 0L
arg.getValue1() === 0 // arg.getValue1()Est un nombre(0)Et le résultat est vrai
//Arg du côté Java.getValue1()Si est 0L
arg.getValue1() === 0 // arg.getValue1()Est un objet(0)Et le résultat est faux
En d'autres termes, même si le type de la valeur passée du côté Java n'a pas changé avec long
, lorsque la version Java passe de 8u91
ou moins à 8u92
ou plus, le type du côté JS mappé par Nashorn seraNumber. Il passe de
à ʻObject. En conséquence, dans le code ci-dessus, le résultat retourné par l'opération d'égalité exacte
===change, la division par zéro que l'on essayait d'éviter est inévitable et
PositiveInfinity` est mélangée avec la valeur au milieu du calcul. Après cela, tous les calculs sont devenus des valeurs inattendues, les résultats ont été renvoyés du côté Java et une erreur s'est produite.
J'ai senti qu'il était important d'être prêt à douter sans le croire de la tête simplement parce que c'était officiel.
Recommended Posts