0

I'm attempting to write a flexible Class that will allow me to parse Binary Data Structures, using Classes defined in Java.

When I'm working purely with int variables, I'm able to achieve what I want, but as soon as I move on to use something like byte[] as a type, I stumble. See the below example.

public class ReflectionTest {
    public ReflectionTest(MappedByteBuffer buffer, int start) {
        buffer.position(start);
        Field[] fields = this.getClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                if (field.getType().toString().equals("int")) {
                    //Set the value of the int field
                    field.setInt(this, buffer.getInt());
                } else if (field.getType().toString().equals("class [B")) {
                    //Set the value of the byte array...
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class ReflectionTest1 extends ReflectionTest {
    public byte[] Signature = new byte[4];
    public byte[] Version = new byte[4];
    public int Time;

    public ReflectionTest1(MappedByteBuffer buffer, int start) {
        super(buffer,start);
    }
}

public Main() {
    try {
        FileChannel channel = new RandomAccessFile("test.bin", "r").getChannel();
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        ReflectionTest1 test = new ReflectionTest1(buffer,0);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

I'm stumped as to how I can either get the length of the arrays defined in ReflectionTest1 (for example, Signature has a length of 4), and thus read in the correct amount of data from the provided MappedByteBuffer to the field.

Is this even possible in Java? My reasoning is that I have a number of structures, some of which have a large number of elements. Instead of repeating myself (performing a getInt/get per field), I could use Reflection to automatically populate the sub classes fields based upon their type, and length.

There are numerous libraries out there that provide similar functionality, but none that provide the flexibility that I require (at least, from what I could find).

Any assistance or insight is gratefully received! :)

2 Answers 2

2

To access arrays reflectively use java.lang.reflect.Array.

Your code should then read:

 if (int.class.equals(field.getType()) 
 {
   ...
 } 
 else if (field.getType().isArray() && byte.class.equals(field.getType().getComponentType()))
 {
   ...
 }

On the assumption that you don't want to read the whole buffer into the byte array, how you know what size the array is will be proprietary to your serialization mechanism (which will probably make the switch statement invalid - it should be replaced with a switch on values read from the buffer).

A common approach is to write the type first, which then controls how to interpret what comes next. In the case of an array, the what comes next would be the length and then the array content.

In all honesty you are better off using a 3rd party library such as Google's Protocol Buffers, which already covers this and much more.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for your reply - I'm aware that how I'm enumerating the field type is not optimal, and I was going to change it to something very similar to what you've provided, however that does not answer the question of how I'd get the length of an array in a sub class using reflection.
Your edited answer sounds sensible, however I believe I know the root cause of my issue. Variables do not appear to be set to their specified values (i.e. int Time = 10 would, under reflection, be returned as 0). IS this assumption correct, do you know?
Also, thanks for the recommendation of Google's Protocol Buffers - I will give some more time to researching them.
@seidr if you're de-serializing the object from the buffer why would you expect the fields to be set? If they were, there'd be no point in de-serializing in the first place because you'd already have the data. If you look at the docs on ProtoBuf, they explain how the serialization mechanism is implemented, which should give you an idea of what's involved
Ah - there's where I've gotten a bit confused. The data is in a format which I cannot modify (third party struct), so adding serializing helpers such as array length markers is not possible.
|
0

Look at java.lang.reflect.Array, it has all the methods needed to access the length and the individual elements of an array.

7 Comments

Thanks, but I did try to use Array.getLength(field) and Array.getLength(field.get(this)). The first understandably returned an error of 'Argument is not an array'. The second returned a Null Pointer Exception. Is my usage / understanding incorrect?
@seidr the length of an array is dynamic and can't read the field before you set it
You did use Array.getLength(field.getObject()), did you? Because a Field is no array, the object the field points to is...
As in a comment above, can I then assume that even if a sub class sets variables at definition (i.e. int Time = 10), those values are not set upon reflection?
field.getObject is not defined
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.