code: ClassDefinition generate(TypeToken<?> outputType, Schema schema) {
      classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
  
      TypeToken<?> interfaceType = getInterfaceType(outputType);
  
      // Generate the class
      String className = getClassName(interfaceType, schema);
      classType = Type.getObjectType(className);
      classWriter.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL,
                        className, Signatures.getClassSignature(interfaceType),
                        Type.getInternalName(Object.class),
                        new String[]{Type.getInternalName(interfaceType.getRawType())});
  
      // Static schema hash field, for verification
      classWriter.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "SCHEMA_HASH",
                             Type.getDescriptor(String.class), null, schema.getSchemaHash().toString()).visitEnd();
  
      // Schema field
      classWriter.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, "schema",
                             Type.getDescriptor(Schema.class), null, null).visitEnd();
  
      // Encode method
      generateEncode(outputType, schema);
  
      // Constructor
      generateConstructor();
  
      ClassDefinition classDefinition = new ClassDefinition(classWriter.toByteArray(), className);
      // DEBUG block. Uncomment for debug
  //    co.cask.tigon.internal.asm.Debugs.debugByteCode(classDefinition, new java.io.PrintWriter(System.out));
      // End DEBUG block
      return classDefinition;
    }
docs: Generates a {@link DatumWriter} class for encoding data of the given output type with the given schema.
  @param outputType Type information of the output data type.
  @param schema Schema of the output data type.
  @return A {@link co.cask.tigon.internal.asm.ClassDefinition} that contains generated class information.