Javascript required
Skip to content Skip to sidebar Skip to footer

A & a Professional Moving and Cleaners Reviews

Jakarta

Experiment with code that uses the new jakarta.* APIs.

At present that the Djakarta EE projection is planning to release its adjacent version (Dki jakarta EE 9), where the major change is the update of all its APIs to utilise jakarta.* instead of javax.* in the package names, and hence the upshot of breaking binary compatibility, I decided to experiment a little bit with how code that uses javax.* APIs can be dynamically modified (without the need to recompile) so that it runs confronting the target jakarta.* namespace.

You may as well like:  Jakarta EE and the Corking Naming Debate

It would too be a skillful opportunity to learn more about Javassist, which I'll be using to do the renaming at the bytecode level. Note that this post is not intended to suggest a solution to this problem of API compatibility. It only shares experimentation related to the bailiwick.

A Little Scrap of Background

Due to trademark restrictions imposed on the javax.* namespace, Djakarta EE will rename all of its specifications to utilize dki jakarta.* in order to motion frontward with evolving the platform with features as the cloud-native Java platform. A major concern here is astern compatibility for existing applications and frameworks using the javax.* APIs in their lawmaking. So far, this business is not explicitly addressed equally function of the Djakarta EE specification.

About Javassist

Since this postal service deals with the dynamic manipulation of bytecode, one popular tool for the job is Javassist. It is a very powerful and well-maintained library for editing course files and is used by many popular projects in the Java ecosystem. Javassists provides both high-level and low-level APIs to manipulate bytecode. The depression-level API is more flexible and allows editing the raw bytes of the class file, just requires noesis of the structure of a grade file, post-obit the JVM specification. In the example that follows, the low-level API will be used. If you're not familiar with the structure of Coffee bytecode, here's an article that gives an introduction.

Sample Code Using `javax.*`

The starting point is some dummy code that uses an API nether the javax.* namespace (for example, using a Djakarta EE 8 or Coffee EE 8 API). Here's a very simple program:

                      bundle instance.jakartaee;  import javax.json.JsonString;  public form MyJsonString implements JsonString {      @Override     public ValueType getValueType() {         return ValueType.STRING;     }      @Override     public String getString() {         return "examination";     }      @Override     public CharSequence getChars() {         render "exam";     } }  package instance.jakartaee;  import javax.json.JsonString; import javax.json.JsonValue;  public class JakartaEESample {      static JsonValue jsonValue = new MyJsonString();      public static void main(String[] args) {         JsonValue jsonV = new MyJsonString();         System.out.println(((JsonString)jsonV).getString());     } }                  

And so nosotros have some lawmaking that uses the JSON Processing API in a very dummy (it doesn't what it does for the moment — all it matters is that it uses some javax API).

Let'due south disassemble the lawmaking to run into what the bytecode looks like, for example for MyJsonString:

                      javap -5 MyJsonString.class                  
                      Classfile MyJsonString.course   Last modified November 2, 2019; size 800 bytes   MD5 checksum a1f98cde65900b434fd184c4980ea911   Compiled from "MyJsonString.java" public class example.jakartaee.MyJsonString implements javax.json.JsonString   small-scale version: 0   major version: 55   flags: (0x0021) ACC_PUBLIC, ACC_SUPER   this_class: #1                          // case/jakartaee/MyJsonString   super_class: #3                         // coffee/lang/Object   interfaces: one, fields: 0, methods: 4, attributes: 2 Constant puddle:    #ane = Form              #2             // example/jakartaee/MyJsonString    #2 = Utf8               example/jakartaee/MyJsonString    #three = Course              #4             // java/lang/Object    #four = Utf8               java/lang/Object    #5 = Class              #6             // javax/json/JsonString    #6 = Utf8               javax/json/JsonString    #7 = Utf8                   #eight = Utf8               ()V    #9 = Utf8               Lawmaking   #10 = Methodref          #3.#11         // java/lang/Object."":()Five   #11 = NameAndType        #vii:#eight          // "":()V   #12 = Utf8               LineNumberTable   #13 = Utf8               LocalVariableTable   #xiv = Utf8               this   #fifteen = Utf8               Lexample/jakartaee/MyJsonString;   #xvi = Utf8               getValueType   #17 = Utf8               ()Ljavax/json/JsonValue$ValueType;   #18 = Fieldref           #xix.#21        // javax/json/JsonValue$ValueType.STRING:Ljavax/json/JsonValue$ValueType;   #19 = Form              #20            // javax/json/JsonValue$ValueType   #xx = Utf8               javax/json/JsonValue$ValueType   #21 = NameAndType        #22:#23        // Cord:Ljavax/json/JsonValue$ValueType;   #22 = Utf8               STRING   #23 = Utf8               Ljavax/json/JsonValue$ValueType;   #24 = Utf8               getString   #25 = Utf8               ()Ljava/lang/Cord;   #26 = Cord             #27            // test   #27 = Utf8               test   #28 = Utf8               getChars   #29 = Utf8               ()Ljava/lang/CharSequence;   #30 = Utf8               SourceFile   #31 = Utf8               MyJsonString.java   #32 = Utf8               InnerClasses   #33 = Class              #34            // javax/json/JsonValue   #34 = Utf8               javax/json/JsonValue   #35 = Utf8               ValueType {   public example.jakartaee.MyJsonString();     descriptor: ()Five     flags: (0x0001) ACC_PUBLIC     Code:       stack=ane, locals=1, args_size=one          0: aload_0          1: invokespecial #10                 // Method java/lang/Object."":()V          iv: render       LineNumberTable:         line 5: 0       LocalVariableTable:         Outset  Length  Slot  Name   Signature             0       5     0  this   Lexample/jakartaee/MyJsonString;    public javax.json.JsonValue$ValueType getValueType();     descriptor: ()Ljavax/json/JsonValue$ValueType;     flags: (0x0001) ACC_PUBLIC     Lawmaking:       stack=i, locals=one, args_size=1          0: getstatic     #18                 // Field javax/json/JsonValue$ValueType.STRING:Ljavax/json/JsonValue$ValueType;          3: areturn       LineNumberTable:         line ix: 0       LocalVariableTable:         Starting time  Length  Slot  Name   Signature             0       4     0  this   Lexample/jakartaee/MyJsonString;    public java.lang.Cord getString();     descriptor: ()Ljava/lang/Cord;     flags: (0x0001) ACC_PUBLIC     Lawmaking:       stack=1, locals=1, args_size=1          0: ldc           #26                 // String examination          2: areturn       LineNumberTable:         line 14: 0       LocalVariableTable:         Start  Length  Slot  Name   Signature             0       3     0  this   Lexample/jakartaee/MyJsonString;    public java.lang.CharSequence getChars();     descriptor: ()Ljava/lang/CharSequence;     flags: (0x0001) ACC_PUBLIC     Lawmaking:       stack=ane, locals=1, args_size=1          0: ldc           #26                 // Cord test          2: areturn       LineNumberTable:         line 19: 0       LocalVariableTable:         Showtime  Length  Slot  Proper name   Signature             0       3     0  this   Lexample/jakartaee/MyJsonString; } SourceFile: "MyJsonString.java" InnerClasses:   public static final #35= #19 of #33;    // ValueType=class javax/json/JsonValue$ValueType of class javax/json/JsonValue                  

I've shown the full bytecode, only the important thing hither is that you can come across references to javax.json.JsonString and javax.json.JsonValue.ValueType (a nested enum) in the constant pool, which is the long list of shared constants that are used inside method bodies. The constants for these classes are javax/json/JsonString in constant #6, and javax/json/JsonValue$ValueType in abiding #twenty (this is how the JVM names these types).

At that place is as well another reference to javax.* in the bytecode, specifically in the method public javax.json.JsonValue$ValueType getValueType().

If we want to convert this class to utilize djakarta.*, nosotros need to practise two things:

  1. Rename occurrences of javax/json/JsonString and javax/json/JsonValue$ValueType in the abiding pool
  2. Change the descriptor of the method getValueType() so that its render type becomes jakarta.json.JsonValue$ValueType.

We tin practise this using Javassist equally follows:

                      import javassist.*; import javassist.bytecode.*;   ClassPool classPool = ClassPool.getDefault();  CtClass ctClass = classPool.get("example.jakartaee.MyJsonString"); ClassFile classFile = ctClass.getClassFile();  ConstPool constPool = classFile.getConstPool(); constPool.renameClass("javax/json/JsonString", "jakarta/json/JsonString"); constPool.renameClass("javax/json/JsonValue$ValueType", "jakarta/json/JsonValue$ValueType");  MethodInfo getValueTypeMethod = classFile.getMethod("getValueType"); getValueTypeMethod.setDescriptor("()Ljakarta/json/JsonValue$ValueType;");  // overwrite the grade file classFile.write(new DataOutputStream(new FileOutputStream("MyJsonString.class")));                  

The ConstPool.renameClass() handles the renaming within the constant puddle, while the MethodInfo.setDescriptor() modifies the descriptor of the method so that the return type is renamed. Finally, nosotros overwrite the form file (we could also save it to a separate file).

After executing the above lawmaking, the new MyJsonString.class file has the updated bytecode. You can see that it at present has new constants for the dki jakarta.* class and descriptor names, and the method descriptor is also updated:

                      ... #36 = Utf8               jakarta/json/JsonString #37 = Utf8               dki jakarta/json/JsonValue$ValueType #38 = Utf8               Ljakarta/json/JsonValue$ValueType; #39 = Utf8               ()Ljakarta/json/JsonValue$ValueType;  ...  public jakarta.json.JsonValue$ValueType getValueType();   descriptor: ()Ljakarta/json/JsonValue$ValueType;                  

Permit's look at present at the other class file to modify, JakartaEESample.class. In this class, we take a field of type javax.json.JsonValue, and a local variable inside the `main` method of the aforementioned type. We also do a cast to javax.json.JsonString.

Similar to what we did for MyJsonString.class, we can rename these classes in the constant puddle using ConstPool.renameClass(), and we even so accept to modify the descriptor of the field (similar nosotros did for the method getValueType() in MyJsonString.form:

                      CtClass ctClass = classPool.get("example.jakartaee.JakartaEESample");         ClassFile classFile = ctClass.getClassFile();  ConstPool constPool = classFile.getConstPool(); constPool.renameClass("javax/json/JsonString", "jakarta/json/JsonString"); constPool.renameClass("javax/json/JsonValue", "dki jakarta/json/JsonValue");  FieldInfo fieldInfo = classFile.getFields().get(0); fieldInfo.setDescriptor("Ljakarta/json/JsonValue;");  // overwrite the class file classFile.write(new DataOutputStream(new FileOutputStream("JakartaEESample.class")));                  

Afterward executing the higher up lawmaking, the bytecode of JakartaEESample.form is updated with new constants for the dki jakarta.* types (which are in turn referenced in the main method) and with an updated field descriptor:

                      ... #30 = Grade              #47            // jakarta/json/JsonString #31 = Utf8               javax/json/JsonString #32 = InterfaceMethodref #xxx.#33        // jakarta/json/JsonString.getString:()Ljava/lang/Cord; ... #47 = Utf8               jakarta/json/JsonString #48 = Utf8               Ljakarta/json/JsonValue;  static jakarta.json.JsonValue jsonValue;     descriptor: Ljakarta/json/JsonValue;     flags: (0x0008) ACC_STATIC  ... public static void master(java.lang.String[]);     descriptor: ([Ljava/lang/Cord;)5     flags: (0x0009) ACC_PUBLIC, ACC_STATIC     Code:       stack=2, locals=2, args_size=one          0: new           #x                 // course example/jakartaee/MyJsonString          three: dup          iv: invokespecial #12                 // Method example/jakartaee/MyJsonString."":()V          7: astore_1          8: getstatic     #24                 // Field coffee/lang/Organisation.out:Ljava/io/PrintStream;         eleven: aload_1         12: checkcast     #thirty                 // grade jakarta/json/JsonString         15: invokeinterface #32,  1           // InterfaceMethod jakarta/json/JsonString.getString:()Ljava/lang/String;         20: invokevirtual #36                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V         23: return                  

Verifying That the Updated Lawmaking Runs!

Apparently, we desire to make sure that the updated class files can run without whatsoever JVM error. To do this, since nosotros don't have the real jakarta.* API released, we tin can create dummy versions of them:

                      package djakarta.json;  public interface JsonString {      Cord getString(); }  package djakarta.json;  public interface JsonValue {      public enum ValueType {         Array,         OBJECT,         STRING,         NUMBER,         Truthful,         FALSE,         NULL     } }                  

And we can run provide these dummy interfaces on the classpath when running the form files that were updated past Javassist.

Conclusion

Using powerful libraries similar Javassist, dynamic conversion of javax.* referencing code to the new jakarta.* packaging is achievable. You can view the full code here.

Further Reading

Jakarta EE and the Great Naming Fence

Dki jakarta Going Forward

Java EE Without javax: The World Won't Cease This Time Either

Topics:

coffee, djakarta, eclipse, namespace, javax

abelforstationve.blogspot.com

Source: https://dzone.com/articles/from-javax-to-jakarta-a-simple-proof-of-concept