content: package com.alibaba.fastjson2.writer;
  
  import com.alibaba.fastjson2.*;
  import com.alibaba.fastjson2.util.Fnv;
  import com.alibaba.fastjson2.util.TypeUtils;
  
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.math.BigDecimal;
  import java.util.*;
  
  import static com.alibaba.fastjson2.JSONB.Constants.BC_ARRAY_FIX_0;
  import static com.alibaba.fastjson2.util.TypeUtils.CLASS_JSON_ARRAY_1x;
  import static com.alibaba.fastjson2.util.TypeUtils.CLASS_JSON_OBJECT_1x;
  
  final class ObjectWriterImplList
          extends ObjectWriterPrimitiveImpl {
      static final ObjectWriterImplList
              INSTANCE = new ObjectWriterImplList(null, null, null, null, 0);
  
      static final ObjectWriterImplList
              INSTANCE_JSON_ARRAY = new ObjectWriterImplList(JSONArray.class, null, null, null, 0);
      static final ObjectWriterImplList INSTANCE_JSON_ARRAY_1x;
  
      static {
          if (CLASS_JSON_ARRAY_1x == null) {
              INSTANCE_JSON_ARRAY_1x = null;
          } else {
              INSTANCE_JSON_ARRAY_1x = new ObjectWriterImplList(CLASS_JSON_ARRAY_1x, null, null, null, 0);
          }
      }
  
      static final Class CLASS_SUBLIST = new ArrayList().subList(0, 0).getClass();
      static final String TYPE_NAME_ARRAY_LIST = TypeUtils.getTypeName(ArrayList.class);
      static final byte[] TYPE_NAME_JSONB_ARRAY_LIST = JSONB.toBytes(TYPE_NAME_ARRAY_LIST);
      static final long TYPE_NAME_HASH_ARRAY_LIST = Fnv.hashCode64(TYPE_NAME_ARRAY_LIST);
  
      final Class defineClass;
      final Type defineType;
      final Class itemClass;
      final Type itemType;
      final long features;
      final boolean itemClassRefDetect;
      volatile ObjectWriter itemClassWriter;
  
      public ObjectWriterImplList(
              Class defineClass,
              Type defineType,
              Class itemClass,
              Type itemType,
              long features
      ) {
          this.defineClass = defineClass;
          this.defineType = defineType;
          this.itemClass = itemClass;
          this.itemType = itemType;
          this.features = features;
          this.itemClassRefDetect = itemClass != null && !ObjectWriterProvider.isNotReferenceDetect(itemClass);
      }
  
      @Override
      public void writeArrayMappingJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
          if (object == null) {
              jsonWriter.writeArrayNull();
              return;
          }
  
          List list = getList(object);
          Class previousClass = null;
          ObjectWriter previousObjectWriter = null;
  
          jsonWriter.startArray(list.size());
          for (int i = 0; i < list.size(); i++) {
              Object item = list.get(i);
              if (item == null) {
                  jsonWriter.writeNull();
                  continue;
              }
              Class<?> itemClass = item.getClass();
              ObjectWriter itemObjectWriter;
              if (itemClass == previousClass) {
                  itemObjectWriter = previousObjectWriter;
              } else {
                  itemObjectWriter = jsonWriter.getObjectWriter(itemClass);
                  previousClass = itemClass;
                  previousObjectWriter = itemObjectWriter;
              }
  
              itemObjectWriter.writeArrayMappingJSONB(jsonWriter, item, i, this.itemType, this.features | features);
          }
      }
  
      @Override
      public void writeJSONB(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
          if (object == null) {
              jsonWriter.writeArrayNull();
              return;
          }
  
          Class fieldItemClass = null;
          Class fieldClass = null;
          if (fieldType instanceof Class) {
              fieldClass = (Class) fieldType;
          } else if (fieldType == this.defineType) {
              fieldClass = this.itemClass;
          } else if (fieldType instanceof ParameterizedType) {
              ParameterizedType parameterizedType = (ParameterizedType) fieldType;
              Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
              if (actualTypeArguments.length == 1) {
                  Type fieldItemType = actualTypeArguments[0];
                  if (fieldItemType instanceof Class) {
                      fieldItemClass = (Class) fieldItemType;
                  }
              }
  
              Type rawType = parameterizedType.getRawType();
              if (rawType instanceof Class) {
                  fieldClass = (Class) rawType;
              }
          }
  
          Class<?> objectClass = object.getClass();
          if (jsonWriter.isWriteTypeInfo(object, fieldClass, features)) {
              if (objectClass == CLASS_SUBLIST || objectClass == ArrayList.class) {
                  jsonWriter.writeTypeName(TYPE_NAME_JSONB_ARRAY_LIST, TYPE_NAME_HASH_ARRAY_LIST);
              } else {
                  String typeName = TypeUtils.getTypeName(objectClass);
                  jsonWriter.writeTypeName(typeName);
              }
          }
  
          List list = getList(object);
          Class previousClass = null;
          ObjectWriter previousObjectWriter = null;
  
          int size = list.size();
          if (size == 0) {
              jsonWriter.writeRaw(BC_ARRAY_FIX_0);
              return;
          }
  
          boolean beanToArray = jsonWriter.isBeanToArray();
          if (beanToArray) {
              jsonWriter.startArray(size);
              for (int i = 0; i < size; i++) {
                  Object item = list.get(i);
                  if (item == null) {
                      jsonWriter.writeNull();
                      continue;
                  }
                  Class<?> itemClass = item.getClass();
                  ObjectWriter itemObjectWriter;
                  if (itemClass == previousClass) {
                      itemObjectWriter = previousObjectWriter;
                  } else {
                      itemObjectWriter = jsonWriter.getObjectWriter(itemClass);
                      previousClass = itemClass;
                      previousObjectWriter = itemObjectWriter;
                  }
  
                  itemObjectWriter.writeArrayMappingJSONB(jsonWriter, item, i, fieldItemClass, features);
              }
              jsonWriter.endArray();
              return;
          }
  
          JSONWriter.Context context = jsonWriter.context;
  
          jsonWriter.startArray(size);
          for (int i = 0; i < size; i++) {
              Object item = list.get(i);
              if (item == null) {
                  jsonWriter.writeNull();
                  continue;
              }
  
              Class<?> itemClass = item.getClass();
  
              if (itemClass == String.class) {
                  jsonWriter.writeString((String) item);
                  continue;
              }
  
              boolean refDetect = (itemClass == this.itemClass)
                      ? this.itemClassRefDetect && jsonWriter.isRefDetect()
                      : jsonWriter.isRefDetect(item);
  
              ObjectWriter itemObjectWriter;
  
              if (itemClass == this.itemClass && itemClassWriter != null) {
                  itemObjectWriter = itemClassWriter;
              } else if (itemClass == previousClass) {
                  itemObjectWriter = previousObjectWriter;
              } else {
                  if (itemClass == JSONObject.class) {
                      itemObjectWriter = ObjectWriterImplMap.INSTANCE;
                  } else if (itemClass == CLASS_JSON_OBJECT_1x) {
                      itemObjectWriter = ObjectWriterImplMap.INSTANCE_1x;
                  } else if (itemClass == JSONArray.class) {
                      itemObjectWriter = ObjectWriterImplList.INSTANCE_JSON_ARRAY;
                  } else if (itemClass == CLASS_JSON_ARRAY_1x) {
                      itemObjectWriter = ObjectWriterImplList.INSTANCE_JSON_ARRAY_1x;
                  } else {
                      itemObjectWriter = context.getObjectWriter(itemClass);
                  }
  
                  previousClass = itemClass;
                  previousObjectWriter = itemObjectWriter;
                  if (itemClass == this.itemClass) {
                      this.itemClassWriter = itemObjectWriter;
                  }
              }
  
              if (refDetect) {
                  String refPath = jsonWriter.setPath0(i, item);
                  if (refPath != null) {
                      jsonWriter.writeReference(refPath);
                      jsonWriter.popPath0(item);
                      continue;
                  }
              }
  
              itemObjectWriter.writeJSONB(jsonWriter, item, i, this.itemType, this.features);
  
              if (refDetect) {
                  jsonWriter.popPath0(item);
              }
          }
          jsonWriter.endArray();
      }
  
      @Override
      public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
          if (object == null) {
              jsonWriter.writeArrayNull();
              return;
          }
  
          List list = getList(object);
          Class previousClass = null;
          ObjectWriter previousObjectWriter = null;
          boolean previousRefDetect = true;
  
          if (jsonWriter.jsonb) {
              jsonWriter.startArray(list.size());
              for (int i = 0; i < list.size(); i++) {
                  Object item = list.get(i);
                  if (item == null) {
                      jsonWriter.writeNull();
                      continue;
                  }
                  Class<?> itemClass = item.getClass();
                  ObjectWriter itemObjectWriter;
                  if (itemClass == previousClass) {
                      itemObjectWriter = previousObjectWriter;
                  } else {
                      itemObjectWriter = jsonWriter.getObjectWriter(itemClass);
                      previousClass = itemClass;
                      previousObjectWriter = itemObjectWriter;
                  }
  
                  itemObjectWriter.writeJSONB(jsonWriter, item, i, itemType, features);
              }
              return;
          }
  
          JSONWriter.Context context = jsonWriter.context;
          ObjectWriterProvider provider = context.provider;
  
          int size = list.size();
          if (size == 0) {
              jsonWriter.writeRaw('[', ']');
              return;
          }
  
          jsonWriter.startArray();
          for (int i = 0; i < size; i++) {
              if (i != 0) {
                  jsonWriter.writeComma();
              }
  
              Object item = list.get(i);
              if (item == null) {
                  jsonWriter.writeNull();
                  continue;
              }
  
              Class<?> itemClass = item.getClass();
              if (itemClass == String.class) {
                  jsonWriter.writeString((String) item);
                  continue;
              } else if (itemClass == Integer.class) {
                  if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT32_MASK) == 0) {
                      jsonWriter.writeInt32((Integer) item);
                  } else {
                      ObjectWriter valueWriter = provider.getObjectWriter(itemClass, itemClass, false);
                      valueWriter.write(jsonWriter, item, i, Integer.class, features);
                  }
                  continue;
              } else if (itemClass == Long.class) {
                  if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT64_MASK) == 0) {
                      jsonWriter.writeInt64((Long) item);
                  } else {
                      ObjectWriter valueWriter = provider.getObjectWriter(itemClass, itemClass, false);
                      valueWriter.write(jsonWriter, item, i, Long.class, features);
                  }
                  continue;
              } else if (itemClass == Boolean.class) {
                  if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT32_MASK) == 0) {
                      jsonWriter.writeBool((Boolean) item);
                  } else {
                      ObjectWriter valueWriter = provider.getObjectWriter(itemClass, itemClass, false);
                      valueWriter.write(jsonWriter, item, i, Boolean.class, features);
                  }
                  continue;
              } else if (itemClass == BigDecimal.class) {
                  if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DECIMAL_MASK) == 0) {
                      jsonWriter.writeDecimal((BigDecimal) item, features, null);
                  } else {
                      ObjectWriter valueWriter = provider.getObjectWriter(itemClass, itemClass, false);
                      valueWriter.write(jsonWriter, item, i, BigDecimal.class, features);
                  }
                  continue;
              }
  
              boolean refDetect;
              ObjectWriter itemObjectWriter;
  
              if (itemClass == this.itemClass && itemClassWriter != null) {
                  itemObjectWriter = itemClassWriter;
                  refDetect = this.itemClassRefDetect && jsonWriter.isRefDetect();
              } else if (itemClass == previousClass) {
                  itemObjectWriter = previousObjectWriter;
                  refDetect = previousRefDetect;
              } else {
                  if (itemClass == JSONObject.class) {
                      itemObjectWriter = ObjectWriterImplMap.INSTANCE;
                      refDetect = jsonWriter.isRefDetect();
                  } else if (itemClass == CLASS_JSON_OBJECT_1x) {
                      itemObjectWriter = ObjectWriterImplMap.INSTANCE_1x;
                      refDetect = jsonWriter.isRefDetect();
                  } else if (itemClass == JSONArray.class) {
                      itemObjectWriter = ObjectWriterImplList.INSTANCE_JSON_ARRAY;
                      refDetect = jsonWriter.isRefDetect();
                  } else if (itemClass == CLASS_JSON_ARRAY_1x) {
                      itemObjectWriter = ObjectWriterImplList.INSTANCE_JSON_ARRAY_1x;
                      refDetect = jsonWriter.isRefDetect();
                  } else {
                      itemObjectWriter = context.getObjectWriter(itemClass);
                      refDetect = jsonWriter.isRefDetect(item);
                  }
  
                  previousClass = itemClass;
                  previousObjectWriter = itemObjectWriter;
                  previousRefDetect = refDetect;
                  if (itemClass == this.itemClass) {
                      this.itemClassWriter = itemObjectWriter;
                  }
              }
  
              if (refDetect) {
                  String refPath = jsonWriter.setPath(i, item);
                  if (refPath != null) {
                      jsonWriter.writeReference(refPath);
                      jsonWriter.popPath(item);
                      continue;
                  }
              }
  
              itemObjectWriter.write(jsonWriter, item, i, this.itemType, this.features);
  
              if (refDetect) {
                  jsonWriter.popPath(item);
              }
          }
          jsonWriter.endArray();
      }
  
      private List getList(Object object) {
          if (object instanceof List) {
              return (List) object;
          } else if (object instanceof Iterable) {
              final Iterable items = (Iterable) object;
              List list = items instanceof Collection ? new ArrayList(((Collection<?>) items).size()) : new ArrayList();
              for (Object item : items) {
                  list.add(item);
              }
              return list;
          } else {
              throw new JSONException("Can not cast '" + object.getClass() + "' to List");
          }
      }
  }
  