1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DynamoDBくん「KVSだから何でも入れられるよ!」 Javaくん「Java使ってるんだからエンティティの構造しっかり決まってるんでしょ?」

Posted at

FXXXXXXXXXCK!!!

DynamoDBに入ってるJsonオブジェクトをJavaで扱えるようにしたいだけなのに

これが調べても調べても「ちゃんとエンティティ用意すればマッピングしてくれるよ!」って方法しか出てこないんですよ。それDynamoじゃなくてよくね??何のためにKVS使ってると思ってるのさ。

Typeを調べる方法すらない

DynamoDBから引っぱってきたデータは AttributeValue (正確には Map<String, AttributeValue>) という型に入っているんですが、 Javadoc を見るとわかる通り 値の型を調べる方法が無い んですよ。こいつを直接 toString してあげるとDynamoDBでおなじみの N とか S とか入ってるのが見えるんですけど、 なぜかそいつを参照できるメソッドが無い という始末。
(しかも少し前のバージョンでは hasXs() 系のメソッドや hasM() すら無かったからリストがなんのリストなのか直接調べる方法がマジで無かったし Map だった場合は本当にどうしようもなかった)
一応 s() とか n() とかで規定外の型を取り出そうとすると null が返ってくるので、虱潰しに調べるという方法も無くはなかったんですが、 l() が無条件で空リストを返してくる というとんでもない仕様だったのでなんかもうなんかもう

とりあえず書き殴ったコード

目下必要なところだけ書いたけどたりないものだらけだからマジで公式で出して……ほんと……

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

public class DynamoDbUtil {

  private class Type{
    static final String nameString = "string";
    static final String nameNumeric = "numeric";
    static final String nameBoolean = "boolean";
    static final String nameArray = "array";
    static final String nameMap = "map";
  }

  static public Boolean isString (AttributeValue a) {
    return (a.s() != null);
  }

  static public Boolean isNumeric (AttributeValue a) {
    return (a.n() != null);
  }

  static public Boolean isBoolean (AttributeValue a) {
    return (a.bool() != null);
  }

  static public Boolean isBinary (AttributeValue a) {
    return (a.b() != null);
  }

  static public Boolean isNumericList (AttributeValue a) {
    return a.hasNs();
  }

  static public Boolean isStringList (AttributeValue a) {
    return a.hasSs();
  }

  static public Boolean isAnyList (AttributeValue a) {
    return a.hasL();
  }

  static public Boolean isMap (AttributeValue a) {
    return a.hasM();
  }

  static public List<Double> toNumberList (List<AttributeValue> as){
    if(as.get(0).n() == null){
      throw new RuntimeException("its not number");
    }
    List<Double> ds = as.stream().map(a -> Double.parseDouble(a.n())).collect(Collectors.toList());
    return ds;
  }

  static public List<String> toStringList(List<AttributeValue> as){
    if(as.get(0).s() == null){
      throw new RuntimeException("its not string");
    }
    List<String> ss = as.stream().map(a -> a.s()).collect(Collectors.toList());
    return ss;
  }

  static public String toString (AttributeValue a) {
    if(isString(a)){
      return a.s();
    }
    if(isNumeric(a)){
      return a.n();
    }
    if(isBoolean(a)){
      return Boolean.toString(a.bool());
    }
    if(isNumericList(a)){
      return toNumberList(a.l()).toString();
    }
    if (isStringList(a)){
      return toStringList(a.l()).toString();
    }
    throw new RuntimeException("inviled value type");
  }

  static public String type(AttributeValue a){
    if(isNumericList(a) || isStringList(a) || isAnyList(a)){
      return Type.nameArray;
    }
    if(isBoolean(a)){
      return Type.nameBoolean;
    }
    if(isNumeric(a)){
      return Type.nameNumeric;
    }
    if(isString(a)){
      return Type.nameString;
    }
    if(isMap(a)){
      return Type.nameMap;
    }
    throw new RuntimeException("inviled value type");
  }

  static public JsonNode toJsonNode(List<Map<String, AttributeValue>> is){
    ObjectMapper mapper = new ObjectMapper();
    ArrayNode array = mapper.createArrayNode();
    is.forEach((i) ->{
      array.add(toJsonNode(i));
    });
    return array;
  }

  static public JsonNode toJsonNode(Map<String, AttributeValue> i){
    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    i.forEach((k, a) -> {
      switch(type(a)){
        case Type.nameArray:
          node.set(k, toJsonNode_AS(a.l()));
          break;
        case Type.nameBoolean:
          node.put(k, a.bool());
          break;
        case Type.nameNumeric:
          node.put(k, Integer.parseInt(a.n()));
          break;
        case Type.nameMap:
          node.set(k, toJsonNode(a.m()));
        default:
          node.put(k, a.s());
      }
    });

    return node;
  }

  static public JsonNode toJsonNode_AS(List<AttributeValue> as){
    ObjectMapper mapper = new ObjectMapper();
    ArrayNode array = mapper.createArrayNode();
    as.forEach((a) -> {
      logger.debug(type(a));
      switch(type(a)){
        case Type.nameArray:
          array.add(toJsonNode_AS(a.l()));
          break;
        case Type.nameBoolean:
          array.add(a.bool());
          break;
        case Type.nameNumeric:
          array.add(Integer.parseInt(a.n()));
          break;
        case Type.nameMap:
          array.add(toJsonNode(a.m())); 
        default:
          array.add(a.s());
      }
    });
    return array;
  }
}

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?