[백업][가리사니] 자바 고정크기 전문통신 (프로토콜) 라이브러리 : c언어 구조체 < > char[] 해당
java

이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.

서론

C언어의 구조체 <-> char[] 가 간단한데 비해 자바에서는 매우 복잡하기 때문에 구현해본 라이브러리 입니다.

오픈소스

준비

maven

<dependency>
  <groupId>me.saro</groupId>
  <artifactId>commons</artifactId>
  <version>3.0.3</version>
</dependency>

gradle

compile 'me.saro:commons:3.0.3'

텍스트 전문

public class FixedDataTest {

    @Test
    public void text() throws UnsupportedEncodingException {
        FixedDataFormat<TextStruct> format = FixedDataFormat.create(TextStruct.class, TextStruct::new);

        TextStruct ts = new TextStruct((byte)-1/* -1 == 255 */, (short)-321, 32123, -21L, 12.3F, -342.5D, "가나다", "abc");

        byte[] bytes = format.toBytes(ts);
        assertEquals(bytes.length, 100);

        String text = new String(bytes, "UTF-8");
        System.out.println(text);
        assertEquals(text, "255-321   0000007d7b-21                 12.3                -342.5              가나다        abc");

        TextStruct ts2 = format.toClass(text.getBytes("UTF-8"));
        System.out.println(ts2);
        assertEquals(ts, ts2);
    }

    @Data
    @FixedData(size=100, fill=0, charset="UTF-8")
    @NoArgsConstructor
    @AllArgsConstructor
    public static class TextStruct {

        @FixedText(offset=0, length=3, unsigned=true)
        byte byteData;

        @FixedText(offset=3, length=7)
        Short shortData;

        @FixedText(offset=10, length=10, radix=16, fill='0', align=FixedTextAlign.right)
        int intData;

        @FixedText(offset=20, length=20)
        long longData;

        @FixedText(offset=40, length=20)
        float floatData;

        @FixedText(offset=60, length=20)
        double doubleData;

        @FixedText(offset=80, length=10)
        String leftText;

        @FixedText(offset=90, length=10, align=FixedTextAlign.right)
        String rightText;
    }
}

바이너리 전문

public class FixedDataTest {

    @Test
    public void binary() {
        FixedDataFormat<BinaryStruct> format = FixedDataFormat.create(BinaryStruct.class, BinaryStruct::new);

        BinaryStruct bs = new BinaryStruct((byte)-1, (short)321, 1234, 76543L, 2.1F, 3.6D, new byte[] {0x1f, 0x3b, 0x33});

        byte[] bytes = format.toBytes(bs);

        assertEquals(bytes.length, 30);

        System.out.println(Bytes.toHex(bytes));
        assertEquals(Bytes.toHex(bytes), "ff0141000004d20000000000012aff40066666400ccccccccccccd1f3b33");

        assertEquals(bs, format.toClass(bytes));

        byte[] bytes2 = new byte[60];
        format.bindBytes(bytes2, 0, bs);
        format.bindBytes(bytes2, 30, bs);

        System.out.println(Bytes.toHex(bytes2));
        assertEquals(Bytes.toHex(bytes2), "ff0141000004d20000000000012aff40066666400ccccccccccccd1f3b33ff0141000004d20000000000012aff40066666400ccccccccccccd1f3b33");

        assertEquals(bs, format.toClass(bytes2, 30));
    }

    @Data
    @FixedData(size=30, fill=0)
    @NoArgsConstructor
    @AllArgsConstructor
    public static class BinaryStruct {

        @FixedBinary(offset=0)
        byte byteData;

        @FixedBinary(offset=1)
        short shortData;

        @FixedBinary(offset=3)
        int intData;

        @FixedBinary(offset=7)
        Long longData; // test long -> Long

        @FixedBinary(offset=15)
        float floatData;

        @FixedBinary(offset=19)
        double doubleData;

        @FixedBinary(offset=27, arrayLength=3)
        byte[] bytesData;
    }
}

혼합전문

public class FixedDataTest {

    @Test
    public void mixed() {
        FixedDataFormat<MixedStruct> format = FixedDataFormat.create(MixedStruct.class, MixedStruct::new);
        MixedStruct ms = new MixedStruct("Yong Seo", "PARK", 1);

        byte[] bytes = format.toBytes(ms);

        assertEquals(bytes.length, 34);

        System.out.println(Bytes.toHex(bytes));
        assertEquals(Bytes.toHex(bytes), "596f6e672053656f202020202020205041524b202020202020202020202000000001");

        assertEquals(ms, format.toClass(bytes, 0));
    }

    @Data
    @FixedData(size=34, charset="UTF-8")
    @NoArgsConstructor
    @AllArgsConstructor
    public static class MixedStruct {

        @FixedText(offset=0, length=15)
        String firstName;

        @FixedText(offset=15, length=15)
        String lastName;

        @FixedBinary(offset=30)
        int memberId;
    }
}

배열예제

public class FixedDataTest {

    @Test
    public void array() {
        FixedDataFormat<ArrayStruct> format = FixedDataFormat.create(ArrayStruct.class, ArrayStruct::new);
        ArrayStruct ms = new ArrayStruct(1, new int[] {2,3,4,5}, Arrays.asList(1L, -2L), new Short[] {21, 72});

        byte[] bytes = format.toBytes(ms);

        assertEquals(bytes.length, 40);

        System.out.println(Bytes.toHex(bytes));

        assertEquals(Bytes.toHex(bytes), "00000001000000020000000300000004000000050000000000000001fffffffffffffffe00150048");

        assertEquals(ms, format.toClass(bytes, 0));

        System.out.println(ms);
        System.out.println(format.toClass(bytes, 0));
    }

    @Data
    @FixedData(size=40)
    @NoArgsConstructor
    @AllArgsConstructor
    public static class ArrayStruct {

        @FixedBinary(offset=0)
        int member1;

        // 속도상 원시 배열이 가장 빠릅니다.
        // 초대량 처리시 원시배열 추천
        @FixedBinary(offset=4, arrayLength=4)
        int[] member2;

        @FixedBinary(offset=20, arrayLength=2)
        List<Long> member3;

        @FixedBinary(offset=36, arrayLength=2)
        Short[] member4;
    }
}

클래스 예제 (테스트중)

public class FixedDataTest {
	@Test
    public void inClass() {

        FixedDataFormat<ParentStruct> format = FixedDataFormat.getInstance(ParentStruct.class);
        ParentStruct ms = new ParentStruct(
                new ChildStruct(2, "단일"),
                new ChildStruct[] {new ChildStruct(32, "배열1"), new ChildStruct(1, "배열2")},
                new ChildStruct[] {new ChildStruct(32, "List3"), new ChildStruct(111, "List 4")},
                -1);

        byte[] bytes = format.toBytes(ms);

        assertEquals(bytes.length, 74);

        System.out.println(Bytes.toHex(bytes));

        assertEquals(Bytes.toHex(bytes), "00000002eb8ba8ec9dbc2020202000000020ebb0b0ec97b43120202000000001ebb0b0ec97b432202020000000204c6973743320202020200000006f4c697374203420202020ffffffff");

        assertEquals(ms, format.toClass(bytes, 0));

        System.out.println(ms);
        System.out.println(format.toClass(bytes, 0));
    }
	@Data
	@FixedData(size=74)
	@NoArgsConstructor
	@AllArgsConstructor
	public static class ParentStruct {

	    @FixedBinary(offset=0)
	    ChildStruct ch;

	    @FixedBinary(offset=14, arrayLength=2)
	    ChildStruct[] chArr;

	    @FixedBinary(offset=42, arrayLength=2)
	    ChildStruct[] chList;

	    @FixedBinary(offset=70)
	    int main;
	}

	@Data
	@FixedData(size=14)
	@NoArgsConstructor
	@AllArgsConstructor
	public static class ChildStruct {

	    @FixedBinary(offset=0)
	    int no;

	    @FixedText(offset=4, length=10)
	    String text;
	}
}