content: package com.alibaba.fastjson2.benchmark.eishay.gen;
  
  import com.alibaba.fastjson2.*;
  import com.alibaba.fastjson2.TypeReference;
  import com.alibaba.fastjson2.benchmark.eishay.EishayFuryWriteNoneCache;
  import com.alibaba.fastjson2.reader.ObjectReaderProvider;
  import com.alibaba.fastjson2.util.DynamicClassLoader;
  import com.alibaba.fastjson2.util.TypeUtils;
  import com.alibaba.fastjson2.writer.ObjectWriterProvider;
  import org.apache.commons.io.IOUtils;
  import org.objectweb.asm.*;
  
  import java.io.InputStream;
  import java.lang.reflect.ParameterizedType;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  
  import static org.objectweb.asm.Opcodes.*;
  
  public class EishayClassGen {
      public Class genMedia(DynamicClassLoader classLoader, String packageName) throws Exception {
          classLoader.definePackage(packageName.replace('/', '.'));
  
          LinkedHashMap<String, byte[]> codes = new LinkedHashMap();
          LinkedHashMap<String, Class> classes = new LinkedHashMap();
  
          genCode(packageName, codes);
          codes.forEach((name, code) -> {
              Class<?> clazz = classLoader.loadClass(name, code, 0, code.length);
              classes.put(name, clazz);
          });
  
          String mediaContentClassName = packageName.replace('/', '.') + ".MediaContent";
          return classes.get(mediaContentClassName);
      }
  
      public void genCode(String packageName, Map<String, byte[]> classBytes) {
          String playerType = packageName + "/Media$Player";
          String playerClassName = playerType.replace('/', '.');
          byte[] playerCode = genEnum(playerType, "JAVA", "FLASH");
          classBytes.put(playerClassName, playerCode);
  
          String mediaType = packageName + "/Media";
          String mediaClassName = mediaType.replace('/', '.');
          byte[] mediaCode = genClass(mediaType,
                  new FieldInfo[]{
                          new FieldInfo("bitrate", long.class),
                          new FieldInfo("duration", long.class),
                          new FieldInfo("format", String.class),
                          new FieldInfo("height", int.class),
                          new FieldInfo("persons", TypeReference.collectionType(List.class, String.class)),
                          new FieldInfo("player", "L" + playerType + ";", null),
                          new FieldInfo("size", long.class),
                          new FieldInfo("title", String.class),
                          new FieldInfo("uri", String.class),
                          new FieldInfo("width", int.class),
                          new FieldInfo("copyright", String.class)
                  });
          classBytes.put(mediaClassName, mediaCode);
  
          String sizeType = packageName + "/Image$Size";
          String sizeClassName = sizeType.replace('/', '.');
          byte[] sizeCode = genEnum(sizeType, "SMALL", "LARGE");
          classBytes.put(sizeClassName, sizeCode);
  
          String imageType = packageName + "/Image";
          String imageClassName = imageType.replace('/', '.');
          byte[] imageCode = genClass(imageType,
                  new FieldInfo[]{
                          new FieldInfo("height", int.class),
                          new FieldInfo("size", "L" + sizeType + ";", null),
                          new FieldInfo("title", String.class),
                          new FieldInfo("uri", String.class),
                          new FieldInfo("width", int.class)
                  }
          );
          classBytes.put(imageClassName, imageCode);
  
          String mediaContentType = packageName + "/MediaContent";
          String mediaContentClassName = mediaContentType.replace('/', '.');
          byte[] mediaContentCode = genClass(mediaContentType,
                  new FieldInfo("media", "L" + mediaType + ";", null),
                  new FieldInfo("images", "Ljava/util/List;", "Ljava/util/List<L" + imageType + ";>;")
          );
          classBytes.put(mediaContentClassName, mediaContentCode);
      }
  
      static class FieldInfo {
          final String name;
          final String desc;
          final String signature;
  
          FieldInfo(String name, java.lang.reflect.Type type) {
              this.name = name;
              Class fieldClass = TypeUtils.getClass(type);
              this.desc = Type.getDescriptor(fieldClass);
              this.signature = getSignature(type);
          }
  
          FieldInfo(String name, String desc, String signature) {
              this.name = name;
              this.desc = desc;
              this.signature = signature;
          }
      }
  
      static String getSignature(java.lang.reflect.Type type) {
          if (type instanceof ParameterizedType) {
              ParameterizedType paramType = (ParameterizedType) type;
              java.lang.reflect.Type rawType = paramType.getRawType();
              java.lang.reflect.Type[] arguments = paramType.getActualTypeArguments();
              if (rawType == List.class) {
                  // "Ljava/util/List<L" + type + ";>;",
                  Class itemType = (Class) arguments[0];
                  String signature = "Ljava/util/List<" + Type.getType(itemType) + ">;";
                  return signature;
              }
          }
          return null;
      }
  
      public byte[] genClass(String type, FieldInfo... fields) {
          ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
          cw.visit(
                  Opcodes.V1_8,
                  ACC_PUBLIC + ACC_SUPER,
                  type,
                  null,
                  "java/lang/Object",
                  new String[] {
                          "java/io/Serializable"
                  }
          );
  
          for (FieldInfo field : fields) {
              FieldVisitor fv = cw.visitField(ACC_PUBLIC, field.name, field.desc, field.signature, null);
              fv.visitEnd();
          }
  
          {
              MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
                      "()V", null);
              mv.visitCode();
              mv.visitVarInsn(ALOAD, 0);
              mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
              mv.visitInsn(RETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
          }
  
          cw.visitEnd();
  
          return cw.toByteArray();
      }
  
      public byte[] genEnum(String type, String... values) {
          ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
          String desc = "L" + type + ";";
          cw.visit(
                  Opcodes.V1_8,
                  ACC_PUBLIC + ACC_FINAL + ACC_SUPER + ACC_ENUM,
                  type,
                  "Ljava/lang/Enum<L" + type + ";>;",
                  "java/lang/Enum",
                  null
          );
  
          for (String value : values) {
              FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM, value, desc, null, null);
              fv.visitEnd();
          }
  
          {
              FieldVisitor fv = cw.visitField(
                      ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
                      "$VALUES", "[" + desc, null, null);
              fv.visitEnd();
          }
  
          {
              MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "<init>", "(Ljava/lang/String;I)V",
                      "()V", null);
              mv.visitCode();
              mv.visitVarInsn(ALOAD, 0);
              mv.visitVarInsn(ALOAD, 1);
              mv.visitVarInsn(ILOAD, 2);
              mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "<init>",
                      "(Ljava/lang/String;I)V");
              mv.visitInsn(RETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
          }
  
          {
              MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "values",
                      "()[" + desc, null, null);
              mv.visitCode();
              mv.visitFieldInsn(GETSTATIC, type, "$VALUES", "[" + desc);
              mv.visitMethodInsn(INVOKEVIRTUAL, "[" + desc, "clone",
                      "()Ljava/lang/Object;");
              mv.visitTypeInsn(CHECKCAST, "[" + desc);
              mv.visitInsn(ARETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
          }
  
          {
              MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "valueOf",
                      "(Ljava/lang/String;)" + desc, null, null);
              mv.visitCode();
              mv.visitLdcInsn(Type.getType(desc));
              mv.visitVarInsn(ALOAD, 0);
              mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf",
                      "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
              mv.visitTypeInsn(CHECKCAST, type);
              mv.visitInsn(ARETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
          }
  
          {
              MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
              mv.visitCode();
  
              for (int i = 0; i < values.length; i++) {
                  String value = values[i];
                  mv.visitTypeInsn(NEW, type);
                  mv.visitInsn(DUP);
                  mv.visitLdcInsn(value);
                  mv.visitLdcInsn(i);
                  mv.visitMethodInsn(INVOKESPECIAL, type, "<init>", "(Ljava/lang/String;I)V");
                  mv.visitFieldInsn(PUTSTATIC, type, value, desc);
              }
  
              mv.visitLdcInsn(values.length);
              mv.visitTypeInsn(ANEWARRAY, type);
  
              for (int i = 0; i < values.length; i++) {
                  String value = values[i];
  
                  mv.visitInsn(DUP);
                  mv.visitLdcInsn(i);
                  mv.visitFieldInsn(GETSTATIC, type, value, desc);
                  mv.visitInsn(AASTORE);
              }
  
              mv.visitFieldInsn(PUTSTATIC, type, "$VALUES", "[" + desc);
              mv.visitInsn(RETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
          }
  
          cw.visitEnd();
  
          return cw.toByteArray();
      }
  
      public byte[][] genFastjsonJSONBBytes(int count, JSONWriter.Feature[] writerFeatures) throws Exception {
          try (InputStream is = EishayFuryWriteNoneCache.class.getClassLoader()
                  .getResourceAsStream("data/eishay.json")
          ) {
              String str = IOUtils.toString(is, "UTF-8");
  
              DynamicClassLoader classLoader = new DynamicClassLoader();
              byte[][] bytes = new byte[count][];
              EishayClassGen gen = new EishayClassGen();
              for (int i = 0; i < count; i++) {
                  String packageName = "com/alibaba/fastjson2/benchmark/eishay" + i;
                  Class objectClass = gen.genMedia(classLoader, packageName);
                  ObjectReaderProvider provider = new ObjectReaderProvider();
                  Object object = JSONReader.of(str, JSONFactory.createReadContext(provider)).read(objectClass);
  
                  ObjectWriterProvider writerProvider = new ObjectWriterProvider();
                  bytes[i] = JSONB.toBytes(object, JSONFactory.createWriteContext(writerProvider, writerFeatures));
              }
              return bytes;
          }
      }
  
      public LinkedHashMap<String, byte[]> genCodes(int count) throws Exception {
          LinkedHashMap<String, byte[]> codeMap = new LinkedHashMap();
          EishayClassGen gen = new EishayClassGen();
          for (int i = 0; i < count; i++) {
              String packageName = "com/alibaba/fastjson2/benchmark/eishay" + i;
              gen.genCode(packageName, codeMap);
          }
          return codeMap;
      }
  
      public byte[][] genFuryBytes(int count) throws Exception {
  //        org.apache.fury.ThreadSafeFury fury = org.apache.fury.Fury.builder()
  //                .withLanguage(org.apache.fury.Language.JAVA)
  //                .withReferenceTracking(true)
  //                .disableSecureMode()
  //                .buildThreadSafeFury();
  //
  //        try (InputStream is = EishayFuryWriteNoneCache.class.getClassLoader()
  //                .getResourceAsStream("data/eishay.json")
  //        ) {
  //            String str = IOUtils.toString(is, "UTF-8");
  //
  //            DynamicClassLoader classLoader = new DynamicClassLoader();
  //            byte[][] bytes = new byte[count][];
  //            EishayClassGen gen = new EishayClassGen();
  //            for (int i = 0; i < count; i++) {
  //                String packageName = "com/alibaba/fastjson2/benchmark/eishay" + i;
  //                Class objectClass = gen.genMedia(classLoader, packageName);
  //                ObjectReaderProvider provider = new ObjectReaderProvider();
  //                Object object = JSONReader.of(str, JSONFactory.createReadContext(provider)).read(objectClass);
  //                bytes[i] = fury.serialize(object);
  //                System.out.println(java.time.LocalDateTime.now() + " write " + i + " done");
  //            }
  //            return bytes;
  //        }
          throw new JSONException("TODO");
      }
  }
  