Пользовательский код c с использованием API-интерфейсов ByteBuffer для установки / получения напрямую для преобразования объекта java в / из ByteBuffer, не работающего с листьями салата / redis - PullRequest
0 голосов
/ 29 января 2020

У меня есть java объект, который имеет некоторые поля int / string / enum

public class Key{
      String name;
      int id;
      Map<Integer, Type> valueMap; //type is an enum

       public void write(final ByteBuffer byteBuffer) throws IOException {
        byteBuffer.clear();
        byte[] nameBytes=  name.getBytes(Charset.forName("UTF-8"));
        byteBuffer.putInt(nameBytes.length);
        byteBuffer.put(nameBytes);
        byteBuffer.putInt(id);
        writeMap(valueMap, byteBuffer);
    }

    private void writeMap(Map<Integer, Type> map, ByteBuffer byteBuffer) throws IOException
    {
        byteBuffer.putInt(map.size());
        for(Map.Entry<Integer, Type> e : map.entrySet()) {
            byteBuffer.putInt(e.getKey().getId());
            byteBuffer.putInt(e.getValue().getId());
        }
    }

    public static Key read(final ByteBuffer byteBuffer) throws IOException {
        int stringLen = byteBuffer.getInt();
        byte[] nameBytes=  new byte[stringLen];
        byteBuffer.get(nameBytes);
        String name= new String(name);
        int id= byteBuffer.getInt();
        Map<Integer, Type> valueMap= readMap(byteBuffer);
        return new Key(name, id, map);
    }

     private static Map<Integer, Type> readMap(ByteBuffer byteBuffer) throws IOException
    {
        int r = byteBuffer.getInt();
        if(r==-1) {
            return ImmutableMap.of();
        } else {
            ImmutableMap.Builder<Integer, Type> mm = ImmutableMap.builder();
            for(int i=0; i<r; i++) {
                int k = byteBuffer.getInt();
                Type v = Type.of(byteBuffer.getInt());
                mm.put(k,v);
            }
            return mm.build();
        }
    }

    .....//constructor and getter/setter present
}


CustomCodec:



public class CustomCodec implements RedisCodec<Key, Set<Long>> {

    @Override
    public Key decodeKey(ByteBuffer bytes) {
            try {
                bytes.flip();
                return Key.read(bytes);
            } catch (IOException e) {
                return null;
            }

    }

    @Override
    public Set<Long> decodeValue(ByteBuffer bytes) {
            bytes.flip();
            int size = bytes.getInt();
            Set<Long> values = new HashSet<Long>();
            for(int i=0; i<size; i++){
                values.add(bytes.getLong());
            }
            return values;
    }


    @Override
    public ByteBuffer encodeKey(Key key) {
        try {
                ByteBuffer byteBuffer = ByteBuffer.allocate(100);
                key.write(byteBuffer);
                return byteBuffer;
            }
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    public ByteBuffer encodeValue(Set<Long> value) {
        try {
                ByteBuffer byteBuffer = ByteBuffer.allocate(value.size() * Long.BYTES + Integer.BYTES);
                byteBuffer.clear();
                byteBuffer.putInt(value.size());
                value.stream().forEach(i -> byteBuffer.putLong(i));
                byteBuffer.flip();
                return byteBuffer;
        } catch (IOException e) {
            return null;
        }
    }


}

Использование этого приводит к BufferUnderFlowException в encodeValue (). Тем не менее, когда я пишу простой тест для подтверждения кодирования и декодирования, он работает нормально. Могу ли я знать, знает ли кто-нибудь, могут ли объекты java быть преобразованы непосредственно в Bytebuffer и могут ли они использоваться в качестве ключей redis с использованием салата?

Я пытался использовать ByteArrayOutputStream / ByteArrayInputStream, и он отлично работает с ним. Но я где-то читал, это должно быть быстрее, если использовать ByteBuffer напрямую.

Заранее большое спасибо!

...