如何在<String, AttributeValue>中Json和Map

问题描述 投票:0回答:4

我想使用 AWS Java SDK 2.0 将编码为 Json 字符串的对象保存到 DynamoDB。

在 AWS Java SDK 1.n 中,可以使用

AttributeValues
将标准 Json 字符串转换为 DynamoDB
Item.fromJSON(myJsonString).toAttributeValues()

虽然可以同时使用两个 SDK,但两个 SDK 版本(

1.11
2.0)定义的 AttributeValue 并不相同,不能互换使用。

是否有任何 AWS 提供的或社区标准的方法可以将 json 字符串/blob 转换为 AWS Java SDK 2.0 的

Map<String, AttributeValue>


请注意,此问题询问的是如何解决 AWS Java SDK 2.0 的问题,而不是 AWS Java SDK 1.n 的 dynamodbv2 模型。如果您认为此问题重复,请仔细检查重复问题/答案的 SDK 版本。

amazon-web-services amazon-dynamodb aws-sdk aws-sdk-java-2.0
4个回答
0
投票

这有点痛苦,但这应该对人们有用:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class DdbUtils {
    private static final ItemParameterizedType ITEM_PARAMETERIZED_TYPE = new ItemParameterizedType();
    private static final TypeReference<Map<String, AttributeValue.Builder>> ITEM_TYPEREF = new TypeReference<>() {
        @Override
        public Type getType() {
            return ITEM_PARAMETERIZED_TYPE;
        }
    };
    private final ObjectMapper objectMapper;

    public DdbUtils() {
        // This is necessary because the fields are commonly "S" or "N", but the AttributeValue builder class
        // expects "s" and "n".
        this(new ObjectMapper().configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true));
    }

    public DdbUtils(ObjectMapper objectMapper) {
        this.objectMapper = Objects.requireNonNull(objectMapper);
    }

    public Map<String, AttributeValue> readItem(String string) throws IOException {
        return buildItemMap(objectMapper.readValue(string, ITEM_TYPEREF));
    }

    public Map<String, AttributeValue> readItem(InputStream inputStream) throws IOException {
        return buildItemMap(objectMapper.readValue(inputStream, ITEM_TYPEREF));
    }

    public Map<String, AttributeValue> convertItem(Object object) {
        return buildItemMap(objectMapper.convertValue(object, ITEM_TYPEREF));
    }

    // ObjectMapper has a lot of methods; feel free to create more *Item methods right here.

    private Map<String, AttributeValue> buildItemMap(Map<String, AttributeValue.Builder> map) {
        return map.entrySet().stream()
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                entry -> entry.getValue().build()
            ));
    }

    // Map<String, AttributeValue.Builder>
    private static class ItemParameterizedType implements ParameterizedType {
        @Override
        public Type getRawType() {
            return Map.class;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return new Type[] { String.class, AttributeValue.serializableBuilderClass() };
        }

        @Override
        public Type getOwnerType() {
            return null;
        }
    }
}

用途:

DdbUtils ddbUtils = new DdbUtils();
Map<String, AttributeValue> item = ddbUtils.readItem(/* whatever */);

使用 AWS Java SDK v2、Jackson 2.12 和 Java 17。


-1
投票

将 JSON 转换为 DynamoDB 的 AttributeValue 的示例

    String productString = readFileFromResources("data/categoryFix.json");
    HashMap<String,Object> result = new ObjectMapper().readValue(productString, HashMap.class);
    Map<String, AttributeValue> attributes = InternalUtils.fromSimpleMap(result);

即使InternalUtils已被弃用,上述代码也运行良好。


-1
投票

InternalUtils
已被弃用,但下面的代码工作正常,并且还显示了如何将其转换为
PutItemResult

HashMap responseMap = objectMapper.readValue(responseBody, HashMap.class);
            Map<String, AttributeValue> attributes = InternalUtils.fromSimpleMap(responseMap);

            PutItemResult result = new PutItemResult();
            result.setAttributes(attributes);

-1
投票

这里有几种方法可以做到这一点(在 Kotlin 中),具体取决于您是使用简单的 JSON 还是 DynamoDB json:

import com.amazonaws.services.dynamodbv2.document.ItemUtils
import com.amazonaws.services.dynamodbv2.model.AttributeValue
import com.fasterxml.jackson.core.type.TypeReference

...
val objectMapper = ObjectMapper().apply {
    configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
}

...

// Method 1 - simple JSON
val obj1: MutableMap<String, AttributeValue> = ItemUtils.fromSimpleMap(
    objectMapper.readValue(
        """
                {
                 "fruits": ["apple", "pear"],
                 "user": { "name": "Bob" }
                }
            """,
        object : TypeReference<Map<String, Any>>() {})
)

// Method 2 - DynamoDB JSON
val obj2: Map<String, AttributeValue> =
    objectMapper.readValue("""
        {
         "fruits": {
          "L": [
             { 
              "S": "apple"
             },
             { 
              "S": "pear"
             }
          ]
         },
         "user": {
            "M": {
             "name": {
              "S": "Bob"
             }
            }
           }
        }
    """.trimIndent(),
    object : TypeReference<Map<String, AttributeValue>>() {}
)
© www.soinside.com 2019 - 2024. All rights reserved.