docs: @Override
      public void visitBeanDefinitionEnd() {
          if (constructorArgumentTypes == null) {
              throw new IllegalStateException("The method visitBeanDefinitionConstructor(..) should be called at least once");
          }
          Type[] interceptorTypes = getObjectTypes(this.interceptorTypes);
          this.constructArgumentMetadata = new LinkedHashMap<>(this.constructArgumentMetadata);
          this.constructArgumentMetadata.put("interceptors", new DefaultAnnotationMetadata() {{
              addDeclaredAnnotation(io.micronaut.context.annotation.Type.class.getName(), Collections.singletonMap(
                  "value", Arrays.stream(interceptorTypes).map(t -> new AnnotationClassValue(t.getClassName())).toArray()
              ));
          }});
          String constructorDescriptor = getConstructorDescriptor(constructorNewArgumentTypes.values());
          ClassWriter proxyClassWriter = this.classWriter;
          this.constructorWriter = proxyClassWriter.visitMethod(
              ACC_PUBLIC,
              CONSTRUCTOR_NAME,
              constructorDescriptor,
              null,
              null);
  
          // Add the interceptor @Type(..) annotation
          AnnotationVisitor interceptorTypeAnn = constructorWriter.visitParameterAnnotation(
              interceptorArgumentIndex, Type.getDescriptor(io.micronaut.context.annotation.Type.class), true
          ).visitArray("value");
          for (Type interceptorType : interceptorTypes) {
              interceptorTypeAnn.visit(null, interceptorType);
          }
          interceptorTypeAnn.visitEnd();
  
          this.constructorGenerator = new GeneratorAdapter(constructorWriter, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor);
          GeneratorAdapter proxyConstructorGenerator = this.constructorGenerator;
  
          proxyConstructorGenerator.loadThis();
          if (isInterface) {
              proxyConstructorGenerator.invokeConstructor(TYPE_OBJECT, METHOD_DEFAULT_CONSTRUCTOR);
          } else {
              Collection<Object> existingArguments = constructorArgumentTypes.values();
              for (int i = 0; i < existingArguments.size(); i++) {
                  proxyConstructorGenerator.loadArg(i);
              }
              String superConstructorDescriptor = getConstructorDescriptor(existingArguments);
              proxyConstructorGenerator.invokeConstructor(getTypeReference(targetClassFullName), new Method(CONSTRUCTOR_NAME, superConstructorDescriptor));
          }
  
          proxyBeanDefinitionWriter.visitBeanDefinitionConstructor(
              constructorAnnotationMedata,
              constructorRequriesReflection,
              constructorNewArgumentTypes,
              constructArgumentMetadata,
              constructorGenericTypes);
  
          GeneratorAdapter targetDefinitionGenerator = null;
          GeneratorAdapter targetTypeGenerator = null;
          if (parentWriter != null) {
              proxyBeanDefinitionWriter.visitBeanDefinitionInterface(ProxyBeanDefinition.class);
              ClassVisitor pcw = proxyBeanDefinitionWriter.getClassWriter();
              targetDefinitionGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC,
                  METHOD_PROXY_TARGET_TYPE.getName(),
                  METHOD_PROXY_TARGET_TYPE.getDescriptor(),
                  null, null
  
              ), ACC_PUBLIC, METHOD_PROXY_TARGET_TYPE.getName(), METHOD_PROXY_TARGET_TYPE.getDescriptor());
              targetDefinitionGenerator.loadThis();
              targetDefinitionGenerator.push(getTypeReference(parentWriter.getBeanDefinitionName()));
              targetDefinitionGenerator.returnValue();
  
  
              targetTypeGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC,
                      METHOD_PROXY_TARGET_CLASS.getName(),
                      METHOD_PROXY_TARGET_CLASS.getDescriptor(),
                      null, null
  
              ), ACC_PUBLIC, METHOD_PROXY_TARGET_CLASS.getName(), METHOD_PROXY_TARGET_CLASS.getDescriptor());
              targetTypeGenerator.loadThis();
              targetTypeGenerator.push(getTypeReference(parentWriter.getBeanTypeName()));
              targetTypeGenerator.returnValue();
          }
  
          Class interceptedInterface = isIntroduction ? Introduced.class : Intercepted.class;
          Type targetType = getTypeReference(targetClassFullName);
  
          // add the $beanLocator field
          if (isProxyTarget) {
              proxyClassWriter.visitField(
                  ACC_PRIVATE | ACC_FINAL,
                  FIELD_BEAN_LOCATOR,
                  TYPE_BEAN_LOCATOR.getDescriptor(),
                  null,
                  null
              );
  
              // add the $beanQualifier field
              proxyClassWriter.visitField(
                      ACC_PRIVATE,
                      FIELD_BEAN_QUALIFIER,
                      Type.getType(Qualifier.class).getDescriptor(),
                      null,
                      null
              );
  
              writeWithQualifierMethod(proxyClassWriter);
  
              if (lazy) {
                  interceptedInterface = InterceptedProxy.class;
              } else {
                  interceptedInterface = hotswap ? HotSwappableInterceptedProxy.class : InterceptedProxy.class;
  
                  // add the $target field for the target bean
                  int modifiers = hotswap ? ACC_PRIVATE : ACC_PRIVATE | ACC_FINAL;
                  proxyClassWriter.visitField(
                      modifiers,
                      FIELD_TARGET,
                      targetType.getDescriptor(),
                      null,
                      null
                  );
                  if (hotswap) {
                      // Add ReadWriteLock field
                      // private final ReentrantReadWriteLock $target_rwl = new ReentrantReadWriteLock();
                      proxyClassWriter.visitField(
                          ACC_PRIVATE | ACC_FINAL,
                          FIELD_READ_WRITE_LOCK,
                          TYPE_READ_WRITE_LOCK.getDescriptor(),
                          null, null
                      );
                      proxyConstructorGenerator.loadThis();
                      pushNewInstance(proxyConstructorGenerator, TYPE_READ_WRITE_LOCK);
                      proxyConstructorGenerator.putField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
  
                      // Add Read Lock field
                      // private final Lock $target_rl = $target_rwl.readLock();
                      proxyClassWriter.visitField(
                          ACC_PRIVATE | ACC_FINAL,
                          FIELD_READ_LOCK,
                          TYPE_LOCK.getDescriptor(),
                          null, null
                      );
                      proxyConstructorGenerator.loadThis();
                      proxyConstructorGenerator.loadThis();
                      proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
                      proxyConstructorGenerator.invokeInterface(
                          Type.getType(ReadWriteLock.class),
                          Method.getMethod(Lock.class.getName() + " readLock()")
                      );
                      proxyConstructorGenerator.putField(proxyType, FIELD_READ_LOCK, TYPE_LOCK);
  
                      // Add Write Lock field
                      // private final Lock $target_wl = $target_rwl.writeLock();
                      proxyClassWriter.visitField(
                          ACC_PRIVATE | ACC_FINAL,
                          FIELD_WRITE_LOCK,
                          Type.getDescriptor(Lock.class),
                          null, null
                      );
  
                      proxyConstructorGenerator.loadThis();
                      proxyConstructorGenerator.loadThis();
                      proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
                      proxyConstructorGenerator.invokeInterface(
                          Type.getType(ReadWriteLock.class),
                          Method.getMethod(Lock.class.getName() + " writeLock()")
                      );
                      proxyConstructorGenerator.putField(proxyType, FIELD_WRITE_LOCK, TYPE_LOCK);
                  }
              }
              // assign the bean locator
              proxyConstructorGenerator.loadThis();
              proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
              proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_LOCATOR, TYPE_BEAN_LOCATOR);
  
  
              Method resolveTargetMethodDesc = writeResolveTargetMethod(proxyClassWriter, targetType);
  
              if (!lazy) {
                  proxyConstructorGenerator.loadThis();
                  proxyConstructorGenerator.loadThis();
                  proxyConstructorGenerator.invokeVirtual(proxyType, resolveTargetMethodDesc);
                  proxyConstructorGenerator.putField(proxyType, FIELD_TARGET, targetType);
              }
  
              // Write the Object interceptedTarget() method
              writeInterceptedTargetMethod(proxyClassWriter, targetType, resolveTargetMethodDesc);
  
              // Write the swap method
              // e. T swap(T newInstance);
              if (hotswap && !lazy) {
                  writeSwapMethod(proxyClassWriter, targetType);
              }
          }
  
          String[] interfaces = getImplementedInterfaceInternalNames();
          if (isInterface && implementInterface) {
              String[] adviceInterfaces = {
                  getInternalName(targetClassFullName),
                  Type.getInternalName(interceptedInterface)
              };
              interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
          } else {
              String[] adviceInterfaces = {Type.getInternalName(interceptedInterface)};
              interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
          }
          proxyClassWriter.visit(V1_8, ACC_SYNTHETIC,
              proxyInternalName,
              null,
              isInterface ? TYPE_OBJECT.getInternalName() : getTypeReference(targetClassFullName).getInternalName(),
              interfaces);
  
          // set $proxyMethods field
          proxyConstructorGenerator.loadThis();
          proxyConstructorGenerator.push(proxyMethodCount);
          proxyConstructorGenerator.newArray(EXECUTABLE_METHOD_TYPE);
          proxyConstructorGenerator.putField(
              proxyType,
              FIELD_PROXY_METHODS,
              FIELD_TYPE_PROXY_METHODS
          );
  
          // set $interceptors field
          proxyConstructorGenerator.loadThis();
          proxyConstructorGenerator.push(proxyMethodCount);
          proxyConstructorGenerator.newArray(INTERCEPTOR_ARRAY_TYPE);
          proxyConstructorGenerator.putField(
              proxyType,
              FIELD_INTERCEPTORS,
              FIELD_TYPE_INTERCEPTORS
          );
  
          // now initialize the held values
          if (isProxyTarget) {
              if (proxyTargetMethods.size() == proxyMethodCount) {
  
                  Iterator<MethodRef> iterator = proxyTargetMethods.iterator();
                  for (int i = 0; i < proxyMethodCount; i++) {
                      MethodRef methodRef = iterator.next();
  
                      // The following will initialize the array of $proxyMethod instances
                      // Eg. this.$proxyMethods[0] = $PARENT_BEAN.getRequiredMethod("test", new Class[]{String.class});
                      proxyConstructorGenerator.loadThis();
  
                      // Step 1: dereference the array - this.$proxyMethods[0]
                      proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
                      proxyConstructorGenerator.push(i);
  
                      // Step 2: lookup the Method instance from the declaring type
                      // context.getProxyTargetMethod("test", new Class[]{String.class});
                      proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
  
                      proxyConstructorGenerator.push(targetType);
  
                      pushMethodNameAndTypesArguments(proxyConstructorGenerator, methodRef.name, methodRef.argumentTypes);
                      proxyConstructorGenerator.invokeInterface(
                          Type.getType(ExecutionHandleLocator.class),
                          METHOD_GET_PROXY_TARGET
                      );
                      // Step 3: store the result in the array
                      proxyConstructorGenerator.visitInsn(AASTORE);
  
                      // Step 4: Resolve the interceptors
                      // this.$interceptors[0] = InterceptorChain.resolveAroundInterceptors(this.$proxyMethods[0], var2);
                      pushResolveInterceptorsCall(proxyConstructorGenerator, i);
                  }
              }
          } else {
  
              for (int i = 0; i < proxyMethodCount; i++) {
                  ExecutableMethodWriter executableMethodWriter = proxiedMethods.get(i);
  
                  // The following will initialize the array of $proxyMethod instances
                  // Eg. this.proxyMethods[0] = new $blah0();
                  proxyConstructorGenerator.loadThis();
                  proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
                  proxyConstructorGenerator.push(i);
                  Type methodType = Type.getObjectType(executableMethodWriter.getInternalName());
                  proxyConstructorGenerator.newInstance(methodType);
                  proxyConstructorGenerator.dup();
                  proxyConstructorGenerator.loadThis();
                  proxyConstructorGenerator.invokeConstructor(methodType, new Method(CONSTRUCTOR_NAME, getConstructorDescriptor(proxyFullName)));
                  proxyConstructorGenerator.visitInsn(AASTORE);
                  pushResolveInterceptorsCall(proxyConstructorGenerator, i);
              }
          }
  
          for (Runnable fieldInjectionPoint : deferredInjectionPoints) {
              fieldInjectionPoint.run();
          }
  
          constructorWriter.visitInsn(RETURN);
          constructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
  
          this.constructorWriter.visitEnd();
          proxyBeanDefinitionWriter.visitBeanDefinitionEnd();
          if (targetDefinitionGenerator != null) {
              targetDefinitionGenerator.visitMaxs(1, 1);
              targetDefinitionGenerator.visitEnd();
          }
  
          if (targetTypeGenerator != null) {
              targetTypeGenerator.visitMaxs(1, 1);
              targetTypeGenerator.visitEnd();
          }
  
  
          proxyClassWriter.visitEnd();
      }