修订 ClassInfo 对 classId 和 instanceId采用正整数进行输出
parent
e6c06e8d10
commit
9a4dc656da
|
@ -40,7 +40,7 @@ public class JfireSEImpl implements JfireSE
|
|||
dyncmicClassId = staticClassId + 1;
|
||||
}
|
||||
|
||||
public ClassInfo getForSerialize(Class<?> clazz)
|
||||
public ClassInfo getOrCreateClassInfo(Class<?> clazz)
|
||||
{
|
||||
if (classInfoCache != null && classInfoCache.getClazz() == clazz)
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ public class JfireSEImpl implements JfireSE
|
|||
byteArray.clear();
|
||||
return array;
|
||||
}
|
||||
ClassInfo classInfo = getForSerialize(instance.getClass());
|
||||
ClassInfo classInfo = getOrCreateClassInfo(instance.getClass());
|
||||
classInfo.write(byteArray, instance);
|
||||
byte[] array = byteArray.toArray();
|
||||
byteArray.clear();
|
||||
|
@ -107,38 +107,38 @@ public class JfireSEImpl implements JfireSE
|
|||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = stream.readBytesWithSizeEmbedded();
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classNameBytes, classId);
|
||||
int classId = stream.readPositiveVarInt();
|
||||
ClassInfo classInfo = find(classNameBytes, classId);
|
||||
return classInfo.readWithTrack(stream);
|
||||
}
|
||||
case JfireSE.NAME_ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = stream.readBytesWithSizeEmbedded();
|
||||
int classId = stream.readVarInt();
|
||||
return getForDeSerialize(classNameBytes, classId).readWithoutTrack(stream);
|
||||
int classId = stream.readPositiveVarInt();
|
||||
return find(classNameBytes, classId).readWithoutTrack(stream);
|
||||
}
|
||||
case JfireSE.ID_CONTENT_TRACK ->
|
||||
{
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classId);
|
||||
int classId = stream.readPositiveVarInt();
|
||||
ClassInfo classInfo = find(classId);
|
||||
return classInfo.readWithTrack(stream);
|
||||
}
|
||||
case JfireSE.ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
int classId = stream.readVarInt();
|
||||
ClassInfo classInfo = getForDeSerialize(classId);
|
||||
int classId = stream.readPositiveVarInt();
|
||||
ClassInfo classInfo = find(classId);
|
||||
return classInfo.readWithoutTrack(stream);
|
||||
}
|
||||
default -> throw new RuntimeException("未知的序列化类型");
|
||||
}
|
||||
}
|
||||
|
||||
public ClassInfo getForDeSerialize(byte[] classNameBytes, int classId)
|
||||
public ClassInfo find(byte[] classNameBytes, int classId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(new String(classNameBytes, StandardCharsets.UTF_8));
|
||||
ClassInfo classInfo = getForSerialize(clazz);
|
||||
ClassInfo classInfo = getOrCreateClassInfo(clazz);
|
||||
if (deSerializedClassInfos == null)
|
||||
{
|
||||
deSerializedClassInfos = new ClassInfo[classId + 1];
|
||||
|
@ -165,7 +165,7 @@ public class JfireSEImpl implements JfireSE
|
|||
}
|
||||
}
|
||||
|
||||
public ClassInfo getForDeSerialize(int classId)
|
||||
public ClassInfo find(int classId)
|
||||
{
|
||||
return deSerializedClassInfos[classId];
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public abstract class ClassInfo
|
|||
else
|
||||
{
|
||||
byteArray.put(JfireSE.INSTANCE_ID);
|
||||
byteArray.writeVarInt(index);
|
||||
byteArray.writePositiveVarInt(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -39,7 +39,7 @@ public class DynamicClassInfo extends ClassInfo
|
|||
addTracking(instance);
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_TRACK);
|
||||
byteArray.writeBytesWithSizeEmbedded(classNameBytes);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
|
@ -48,14 +48,14 @@ public class DynamicClassInfo extends ClassInfo
|
|||
if (i == -1)
|
||||
{
|
||||
byteArray.put(JfireSE.ID_CONTENT_TRACK);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_INSTANCE_ID);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writeVarInt(i);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
byteArray.writePositiveVarInt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,13 +66,13 @@ public class DynamicClassInfo extends ClassInfo
|
|||
firstSerialized = true;
|
||||
byteArray.put(JfireSE.NAME_ID_CONTENT_UN_TRACK);
|
||||
byteArray.writeBytesWithSizeEmbedded(classNameBytes);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_CONTENT_UN_TRACK);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,27 +19,21 @@ public class StaticClasInfo extends ClassInfo
|
|||
if (i == -1)
|
||||
{
|
||||
byteArray.put(JfireSE.ID_CONTENT_TRACK);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_INSTANCE_ID);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writeVarInt(i);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
byteArray.writePositiveVarInt(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.put(JfireSE.ID_CONTENT_UN_TRACK);
|
||||
byteArray.writeVarInt(classId);
|
||||
byteArray.writePositiveVarInt(classId);
|
||||
serializer.writeBytes(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readWithTrack(ByteArray byteArray)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,13 @@ import com.jfirer.se2.ByteArray;
|
|||
|
||||
public interface Serializer
|
||||
{
|
||||
/**
|
||||
* 输出实例的内容本身,不包含标志位
|
||||
*
|
||||
* @param byteArray
|
||||
* @param instance
|
||||
*/
|
||||
void writeBytes(ByteArray byteArray, Object instance);
|
||||
|
||||
void read(ByteArray stream, Object instance);
|
||||
|
||||
|
||||
void read(ByteArray byteArray, Object instance);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package com.jfirer.se2.serializer.impl;
|
||||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import com.jfirer.se2.JfireSEImpl;
|
||||
import com.jfirer.se2.classinfo.ClassInfo;
|
||||
import com.jfirer.se2.serializer.Serializer;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public class ArraySerializer<T> implements Serializer
|
||||
{
|
||||
private Class<?> componentType;
|
||||
private final boolean isFinal;
|
||||
private final ClassInfo typeDefinedClassInfo;
|
||||
private JfireSEImpl jfireSE;
|
||||
|
||||
public ArraySerializer(Class<T[]> clazz, JfireSEImpl jfireSE)
|
||||
{
|
||||
this.jfireSE = jfireSE;
|
||||
this.componentType = clazz.getComponentType();
|
||||
typeDefinedClassInfo = jfireSE.getOrCreateClassInfo(componentType);
|
||||
isFinal = Modifier.isFinal(componentType.getModifiers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBytes(ByteArray byteArray, Object instance)
|
||||
{
|
||||
T[] arr = (T[]) instance;
|
||||
byteArray.writePositiveVarInt(arr.length);
|
||||
for (T t : arr)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
byteArray.put(JfireSE.NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
Class<?> tClass = t.getClass();
|
||||
if (tClass == typeDefinedClassInfo.getClazz())
|
||||
{
|
||||
typeDefinedClassInfo.writeKnownClazz(byteArray, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassInfo classInfo = jfireSE.getOrCreateClassInfo(tClass);
|
||||
classInfo.write(byteArray, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
int len = byteArray.readPositiveVarInt();
|
||||
T[] arr = (T[]) Array.newInstance(componentType, len);
|
||||
for (int i = 0; i < arr.length; i++)
|
||||
{
|
||||
byte flag = byteArray.get();
|
||||
if (flag == JfireSE.NULL)
|
||||
{
|
||||
arr[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
byte[] bytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int i1 = byteArray.readVarInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
ArraySerializer<Integer> arraySerializer = new ArraySerializer(Integer[].class, (JfireSEImpl) JfireSE.build());
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ public class FinalFieldInfo extends FieldInfo
|
|||
public FinalFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(field);
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
classInfo = jfireSE.getOrCreateClassInfo(field.getType());
|
||||
this.jfireSE = jfireSE;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class FinalFieldInfo extends FieldInfo
|
|||
{
|
||||
case JfireSE.INSTANCE_ID ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
Object property = classInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
|
|
|
@ -41,11 +41,11 @@ public class ObjectSerializer implements Serializer
|
|||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteArray stream, Object instance)
|
||||
public void read(ByteArray byteArray, Object instance)
|
||||
{
|
||||
for (FieldInfo each : fieldInfos)
|
||||
{
|
||||
each.read(stream, instance);
|
||||
each.read(byteArray, instance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,7 +416,7 @@ public class ObjectSerializer implements Serializer
|
|||
FieldModel classInfoModel = new FieldModel(classInfoProperty, ClassInfo.class, classModel);
|
||||
FieldModel firstClassInfoModel = new FieldModel(firstClassInfoProperty, ClassInfo.class, classModel);
|
||||
classModel.addField(classInfoModel, firstClassInfoModel);
|
||||
constructorBody.append(classInfoProperty + "=jfireSE.getForSerialize(((FieldInfo)list.get(" + fieldIndex + ")).getField().getType());\r\n");
|
||||
constructorBody.append(classInfoProperty + "=jfireSE.getOrCreateClassInfo(((FieldInfo)list.get(" + fieldIndex + ")).getField().getType());\r\n");
|
||||
constructorBody.append(" if( ((FieldInfo)list.get(" + fieldIndex + ")).getField().getType().isInterface()) {");
|
||||
constructorBody.append(firstClassInfoProperty + "=null;\r\n}");
|
||||
constructorBody.append("else{\r\n");
|
||||
|
@ -436,7 +436,7 @@ public class ObjectSerializer implements Serializer
|
|||
writeBody.append("}\r\n");
|
||||
writeBody.append("}");
|
||||
writeBody.append("else{");
|
||||
writeBody.append(classInfoProperty + "=" + "jfireSE.getForSerialize(" + objClassName + ");\r\n");
|
||||
writeBody.append(classInfoProperty + "=" + "jfireSE.getOrCreateClassInfo(" + objClassName + ");\r\n");
|
||||
writeBody.append("if(" + classInfoProperty + "==" + firstClassInfoProperty + "){\r\n");
|
||||
writeBody.append(classInfoProperty + ".writeKnownClazz(byteArray," + objName + ");\r\n");
|
||||
writeBody.append("}\r\n");
|
||||
|
@ -454,8 +454,8 @@ public class ObjectSerializer implements Serializer
|
|||
case JfireSE.NAME_ID_CONTENT_TRACK->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = jfireSE.getForDeSerialize(classNameBytes, classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
ClassInfo classInfo = jfireSE.find(classNameBytes, classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -464,8 +464,8 @@ public class ObjectSerializer implements Serializer
|
|||
case JfireSE.NAME_ID_CONTENT_UN_TRACK->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = jfireSE.getForDeSerialize(classNameBytes,classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
ClassInfo classInfo = jfireSE.find(classNameBytes,classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -473,9 +473,9 @@ public class ObjectSerializer implements Serializer
|
|||
readBody.append("""
|
||||
case JfireSE.ID_INSTANCE_ID->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
ClassInfo classInfo = jfireSE.find(classId);
|
||||
Object property = classInfo.getInstanceById(instanceId);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -483,8 +483,8 @@ public class ObjectSerializer implements Serializer
|
|||
readBody.append("""
|
||||
case JfireSE.ID_CONTENT_TRACK->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
ClassInfo classInfo = jfireSE.find(classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -492,8 +492,8 @@ public class ObjectSerializer implements Serializer
|
|||
readBody.append("""
|
||||
case JfireSE.ID_CONTENT_UN_TRACK->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
ClassInfo classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
ClassInfo classInfo = jfireSE.find(classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -501,7 +501,7 @@ public class ObjectSerializer implements Serializer
|
|||
readBody.append("""
|
||||
case JfireSE.INSTANCE_ID ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
Object property = firstClassInfo.getInstanceById(instanceId);
|
||||
UNSAFE.putReference(instance,offset, property);
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ public class ObjectSerializer implements Serializer
|
|||
String classInfoProperty = "classInfo_$_" + fieldIndex;
|
||||
FieldModel classInfoModel = new FieldModel(classInfoProperty, ClassInfo.class, classModel);
|
||||
classModel.addField(classInfoModel);
|
||||
constructorBody.append(classInfoProperty + "=jfireSE.getForSerialize(((FieldInfo)list.get(" + fieldIndex + ")).getField().getType());\r\n");
|
||||
constructorBody.append(classInfoProperty + "=jfireSE.getOrCreateClassInfo(((FieldInfo)list.get(" + fieldIndex + ")).getField().getType());\r\n");
|
||||
writeBody.append("""
|
||||
{
|
||||
Object obj = UNSAFE.getReference(instance,offset);
|
||||
|
@ -557,7 +557,7 @@ public class ObjectSerializer implements Serializer
|
|||
{
|
||||
case JfireSE.INSTANCE_ID ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
Object property = classInfo.getInstanceById(instanceId);
|
||||
UNSAFE.putReference(instance,offset,property);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class VariableFieldInfo extends FieldInfo
|
|||
public VariableFieldInfo(Field field, JfireSEImpl jfireSE)
|
||||
{
|
||||
super(field);
|
||||
classInfo = jfireSE.getForSerialize(field.getType());
|
||||
classInfo = jfireSE.getOrCreateClassInfo(field.getType());
|
||||
this.jfireSE = jfireSE;
|
||||
if (field.getType().isInterface())
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ public class VariableFieldInfo extends FieldInfo
|
|||
}
|
||||
else
|
||||
{
|
||||
classInfo = jfireSE.getForSerialize(objClass);
|
||||
classInfo = jfireSE.getOrCreateClassInfo(objClass);
|
||||
if (classInfo == firstClassInfo)
|
||||
{
|
||||
classInfo.writeKnownClazz(byteArray, obj);
|
||||
|
@ -80,44 +80,44 @@ public class VariableFieldInfo extends FieldInfo
|
|||
case JfireSE.NAME_ID_CONTENT_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classNameBytes, classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
classInfo = jfireSE.find(classNameBytes, classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.NAME_ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
byte[] classNameBytes = byteArray.readBytesWithSizeEmbedded();
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classNameBytes, classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
classInfo = jfireSE.find(classNameBytes, classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.ID_INSTANCE_ID ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
classInfo = jfireSE.find(classId);
|
||||
Object proeprty = classInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, proeprty);
|
||||
}
|
||||
case JfireSE.ID_CONTENT_TRACK ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
classInfo = jfireSE.find(classId);
|
||||
Object property = classInfo.readWithTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.ID_CONTENT_UN_TRACK ->
|
||||
{
|
||||
int classId = byteArray.readVarInt();
|
||||
classInfo = jfireSE.getForDeSerialize(classId);
|
||||
int classId = byteArray.readPositiveVarInt();
|
||||
classInfo = jfireSE.find(classId);
|
||||
Object property = classInfo.readWithoutTrack(byteArray);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
case JfireSE.INSTANCE_ID ->
|
||||
{
|
||||
int instanceId = byteArray.readVarInt();
|
||||
int instanceId = byteArray.readPositiveVarInt();
|
||||
Object property = firstClassInfo.getInstanceById(instanceId);
|
||||
accessor.setObject(instance, property);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.example;
|
|||
|
||||
import com.jfirer.se2.ByteArray;
|
||||
import com.jfirer.se2.JfireSE;
|
||||
import io.fury.Fury;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -36,5 +37,14 @@ public class FunctionTest
|
|||
Assert.assertEquals(sm, testData.getTestDataSm());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3()
|
||||
{
|
||||
Fury fury = Fury.builder().requireClassRegistration(false).build();
|
||||
TestData[] data = new TestData[2];
|
||||
data[0] = new TestData();
|
||||
fury.serialize(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue