Javolution ByteBuffer 问题

发布于 2024-11-27 07:23:02 字数 2408 浏览 3 评论 0原文

我使用 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);
.
.
.
}

在我们的通信类中,在将数据放入套接字之前,我们需要获取 RunScan 对象的 bytes[],但我们在“//<<<<”行中得到 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();

仅返回 RunScan 对象的 8 个字节(来自剩余()方法)ByteBuffer,我认为这就是这两个 Signed32 字段。但是这一行

int cmdSize = scCmd.size();

返回 RunScan 对象的正确长度,其中包括这两个数组的大小。

如果我在声明它们时使用硬编码长度创建这两个数组(而不是在构造函数中“新”它们),则它可以正常工作,没有任何异常。

任何人都可以帮我找出我们的实施出了什么问题吗?

I have the following implementation with 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);
.
.
.
}

In our communication class, before we put data onto socket, we need to get the bytes[] of the RunScan object but we get BufferUnderflowException in the line with "//<<<<<<<":

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;
    }

This method works in other cases. The exception happens because this line,

ByteBuffer cmdBuffer = scCmd.getByteBuffer();

only returns a 8 bytes (from the remaining() method) ByteBuffer of the RunScan object which are those two Signed32 fields, I think. But this line,

int cmdSize = scCmd.size();

returns a right length of the RunScan object which includes the size of those two arrays.

If I create those two array at the time I declare them (not "new" them in the constructor) with hard coded length, it works fine without any exception.

Anybody can help me figure out what's wrong with our implementation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ぃ弥猫深巷。 2024-12-04 07:23:02

我的代码遇到了类似的情况。通常,对于当前的 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]);      
    }
}

然后,您将需要一个两阶段的方法来读取和写入,首先读取/写入标头数据,然后读取/写入主体数据。

抱歉,我目前没有更多详细信息,如果您无法解决此问题,请告诉我,我将深入研究我的代码。

I ran into a similar situation with my code. Generally, with the current Struct object, you cannot have a variable length array defined in the same struct as the member that contains the number of elements in the array.

Try something like this:

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]);      
    }
}

You'll then need a two phase approach to read and write, first read/write the header data, then read/write the body data.

Sorry I don't have more details at this time, if you can't solve this, let me know and I'll dig back through my code.

枫林﹌晚霞¤ 2024-12-04 07:23:02

初始化顺序很重要,它定义了每个字段的位置。要么在声明字段时完成初始化(最常见的情况)。或者,如果您在构造函数中执行此操作,则必须记住构造函数是在成员初始化之后调用的。这是在构造函数中完成初始化的示例:

 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);
     }
}

The initialization order is important has it defines the position of each field. Either your initialization is done when the field is declared (most common case). Or if you do it in the constructor you have to remember that the constructor is called after the member initialization. Here is an example with initialization done in the constructor:

 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);
     }
}
叫思念不要吵 2024-12-04 07:23:02

get() 将移动 ByteBuffer 的位置。

scCmd.getByteBuffer().slice().get(dest) 可能会解决移动位置和意外副作用的问题。

如果 slice() 生成错误的原始缓冲区图片,则 scCmd.getByteBuffer().duplicate().get(dest) 也可能会解决您的问题。

此外,似乎 scCmd.getByteBuffer() 创建了冗余引用,并且您在同一方法中调用源引用和子引用。

如果 scCmd.getByteBuffer() 已经向您传递了 slice(),那么您对这些方法的冗余访问肯定会执行您计划之外的操作。

get() will move the position of the ByteBuffer.

scCmd.getByteBuffer().slice().get(dest) might solve your issue with moving the position and unintended side effects.

scCmd.getByteBuffer().duplicate().get(dest) might also solve your issue if slice() produces the wrong picture of the origin buffer.

Additionally, it appears as though scCmd.getByteBuffer() creates a redundant reference and you are calling the source and child reference in the same method.

If scCmd.getByteBuffer() is already passing you a slice(), your redundant access to these methods is certainly going to do something other than what you planned.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文