Javolution ByteBuffer вопрос
У меня есть следующая реализация с Javolution:
public class RunScan extends Struct
{
public final Signed32 numOfClusters = new Signed32();
public final ClusterData[] clusters;
public final Signed32 numOfRecons = new Signed32();
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons)
{
this.numOfClusters.set(numOfClusters);
this.numOfRecons.set(numOfRecons);
clusters = array(new ClusterData[numOfClusters]);
recons = array(new ReconData[numOfRecons]);
}
}
public class ClusterData extends Struct
{
public final UTF8String scanType = new UTF8String(CommInterfaceFieldConstants.SCAN_TYPE_SIZE);
public final UTF8String patientId = new UTF8String(CommInterfaceFieldConstants.PATIENT_ID_SIZE);
.
.
.
}
public class ReconData extends Struct
{
public final UTF8String patientId = new UTF8String(CommInterfaceFieldConstants.PATIENT_ID_SIZE);
public final UTF8String scanSeriesId = new UTF8String(CommInterfaceFieldConstants.SCAN_SERIES_ID_SIZE);
.
.
.
}
В нашем классе связи перед тем, как поместить данные в сокет, нам нужно получить bytes[] объекта RunScan, но мы получаем BufferUnderflowException в строке с "//<<<<<<<":
private byte[] getCmdBytes(Struct scCmd)
{
ByteBuffer cmdBuffer = scCmd.getByteBuffer();
int cmdSize = scCmd.size();
byte[] cmdBytes = new byte[cmdSize];
if (cmdBuffer.hasArray())
{
int offset = cmdBuffer.arrayOffset() + scCmd.getByteBufferPosition();
System.arraycopy(cmdBuffer.array(), offset, cmdBytes, 0, cmdSize);
}
else
{
String msg = "\n\ncmdBufferRemaining=" + cmdBuffer.remaining() + ", cmdBytesSize=" + cmdBytes.length + "\n\n";
System.out.println(msg);
cmdBuffer.position(scCmd.getByteBufferPosition());
cmdBuffer.get(cmdBytes); //<<<<<<<<<< underFlowException
}
return cmdBytes;
}
Этот метод работает в других случаях. Исключение происходит потому, что эта строка,
ByteBuffer cmdBuffer = scCmd.getByteBuffer();
Я думаю, что возвращает только 8 байтов (из метода оставшегося ()) ByteBuffer объекта RunScan, которые являются теми двумя полями Signed32. Но эта линия,
int cmdSize = scCmd.size();
возвращает правильную длину объекта RunScan, которая включает размер этих двух массивов.
Если я создаю эти два массива в тот момент, когда я объявляю их (не "новые" в конструкторе) с жестко заданной длиной, он работает без каких-либо исключений.
Кто-нибудь может помочь мне понять, что не так с нашей реализацией?
3 ответа
Я столкнулся с аналогичной ситуацией с моим кодом. Как правило, в текущем объекте Struct массив переменной длины не может быть определен в той же структуре, что и элемент, содержащий количество элементов в массиве.
Попробуйте что-то вроде этого:
public class RunScanHeader extends Struct
{
public final Signed32 numOfClusters = new Signed32();
public final Signed32 numOfRecons = new Signed32();
}
public class RunScanBody extends Struct
{
public final ClusterData[] clusters;
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons)
{
clusters = array(new ClusterData[numOfClusters]);
recons = array(new ReconData[numOfRecons]);
}
}
Затем вам потребуется двухфазный подход для чтения и записи, сначала чтение / запись данных заголовка, а затем чтение / запись данных тела.
Извините, у меня нет более подробной информации, если вы не можете решить эту проблему, дайте мне знать, и я вернусь к своему коду.
get()
переместит положение ByteBuffer
,
scCmd.getByteBuffer().slice().get(dest)
может решить вашу проблему с перемещением позиции и непреднамеренными побочными эффектами.
scCmd.getByteBuffer().duplicate().get(dest)
может также решить вашу проблему, если slice()
создает неправильное изображение исходного буфера.
Кроме того, похоже, что scCmd.getByteBuffer()
создает избыточную ссылку, и вы вызываете исходную и дочернюю ссылку в одном методе.
Если scCmd.getByteBuffer()
уже передает вам slice()
Ваш избыточный доступ к этим методам, безусловно, будет делать нечто иное, чем вы запланировали.
Порядок инициализации важен, поскольку он определяет положение каждого поля. Либо ваша инициализация выполняется, когда поле объявлено (наиболее распространенный случай). Или, если вы делаете это в конструкторе, вы должны помнить, что конструктор вызывается после инициализации члена. Вот пример с инициализацией, выполненной в конструкторе:
public class RunScan extends Struct {
public final Signed32 numOfClusters;
public final ClusterData[] clusters;
public final Signed32 numOfRecons;
public final ReconData[] recons ;
public RunScan (int numOfClusters, int numOfRecons) {
// Initialization done in the constructor for all members
// Order is important, it should match the declarative order to ensure proper positioning.
this.numOfClusters = new Signed32();
this.clusters = array(new ClusterData[numOfClusters]);
this.numOfRecons = new Signed32();
this.recons = array(new ReconData[numOfRecons]);
// Only after all the members have been initialized the set method can be used.
this.numOfClusters.set(numOfClusters);
this.numOfRecons.set(numOfRecons);
}
}