java DynamoDB -对象到属性值

cgfeq70w  于 2023-06-28  发布在  Java
关注(0)|答案(5)|浏览(143)

我知道DynamoDBMapper,但在我的情况下,我不能使用它,因为我事先不知道所有的属性。
我有一个JSON,它通过使用Jackson解析器解析为对象的Map:

Map<String, Object> userData = mapper.readValue(new File("user.json"), Map.class);

遍历每个属性,如果DynamoDB AttributeValue支持Boolean、String、Number、Bytes、List等,如何将值转换为AttributeValue
有没有一个有效的方法来做到这一点?现在已经有图书馆了吗?我的简单方法是检查每个值是否是Boolean/String/Number/等类型。然后调用适当的AttributeValue方法,例如:new AttributeValue().withN(value.toString())-这给了我一长串if, else if

beq87vna

beq87vna1#

最后通过查看AWS如何解析JSON来弄清楚
基本上,这是代码:

Item item = new Item().withJSON("document", jsonStr);
    Map<String,AttributeValue> attributes = InternalUtils.toAttributeValues(item);
    return attributes.get("document").getM();

很整洁。

wljmcqd8

wljmcqd82#

以下是一个简单的解决方案,可用于将任何DynamoDB JSON转换为Simple JSON。

//passing the reponse.getItems() 
public static Object getJson(List<Map<String,AttributeValue>> mapList) {
    List<Object> finalJson= new ArrayList();
    for(Map<String,AttributeValue> eachEntry : mapList) {
        finalJson.add(mapToJson(eachEntry));
    }
    return finalJson;
}

//if the map is null then it add the key and value(string) in the finalKeyValueMap
public static Map<String,Object> mapToJson(Map<String,AttributeValue> keyValueMap){
    Map<String,Object> finalKeyValueMap = new HashMap();
    for(Map.Entry<String, AttributeValue> entry : keyValueMap.entrySet()) 
    {
        if(entry.getValue().getM() == null) {
            finalKeyValueMap.put(entry.getKey(),entry.getValue().getS());
        }
        else {
            finalKeyValueMap.put(entry.getKey(),mapToJson(entry.getValue().getM()));
        }
    }
    return finalKeyValueMap;
}

这将以List<Map<String,Object>>的形式生成所需的Json,它是object的子集。

omvjsjqw

omvjsjqw3#

我使用JacksonConverterImplJsonNode转换为Map<String, AttributeValue>

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readValue(jsonString, JsonNode.class);
final JacksonConverter converter = new JacksonConverterImpl();
Map<String, AttributeValue> map = converter.jsonObjectToMap(jsonNode);

希望这有帮助!
谢了,杰

huwehgph

huwehgph4#

对于2.x SDK,我还没有确定SDK提供的等效功能。作为练习,我决定用switch表达式来解决这个问题
此实现将编组Map、记录、原语、字节数组、集合类型,并将在未知类型上调用toString()。我唯一没有实现的数据类型是字节集(BS),因为确定唯一的字节数组值并不是那么简单。
您可以添加对bean属性的支持,但我认为这会容易出错,因此决定默认只支持toString
也包括unmarshal作为练习。

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

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

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

public class AttributeValueConverter {

    public static AttributeValue fromCollection(Collection<? extends Object> c) {
        if (c instanceof Set s && s.stream().allMatch(n -> n instanceof String)) {
            var vals = c.stream()
                .map(n -> (String) n)
                .collect(toList());
            return AttributeValue.fromSs(vals);
        }
        var vals = c.stream()
            .map(x -> marshal(x))
            .collect(toList());
        return AttributeValue.fromL(vals);
    }

    public static AttributeValue fromMap(Map<? extends Object, ? extends Object> m) {
        var vals = new HashMap<String, AttributeValue>();
        m.forEach((k, v) ->
            vals.put(k.toString(), marshal(v))
        );
        return AttributeValue.fromM(vals);
    }

    public static AttributeValue fromRecord(Record r) {
        var vals = new HashMap<String, AttributeValue>();
        var components = r.getClass().getRecordComponents();
        for (var component : components) {
            try {
                vals.put(
                    component.getName(),
                    marshal(component.getAccessor().invoke(r))
                );
            } catch (IllegalAccessException | InvocationTargetException ex) {
                // will happen if the class is not accessible
            }
        }
        return AttributeValue.fromM(vals);
    }

    public static AttributeValue marshal(Object obj) {
        return switch (obj) {
            case null           -> AttributeValue.fromNul(true);
            case Optional opt   -> opt.isPresent()
                                   ? marshal(opt.get())
                                   : AttributeValue.fromNul(true);
            case Boolean b      -> AttributeValue.fromBool(b);
            case Number n       -> AttributeValue.fromN(n.toString());
            case String s       -> AttributeValue.fromS(s);
            // string representations of temporals are mostly what you want
            //case Temporal t     -> AttributeValue.fromS(t.toString());
            case Collection c   -> fromCollection(c);
            case Map m          -> fromMap(m);
            case Record r       -> fromRecord(r);
            case Object o when o.getClass().isArray() -> {
                var ctype = obj.getClass().getComponentType().getTypeName();
                if ("byte".equals(ctype)) {
                    yield AttributeValue.fromB(
                        SdkBytes.fromByteArray((byte[]) obj)
                    );
                }
                yield fromCollection(Arrays.asList((Object[]) obj));
            }
            default -> AttributeValue.fromS(obj.toString());
        };
    }

    private static final Pattern INT_PATTERN = Pattern.compile("^-?[0-9]+$");

    private static Number parseNumber(String n) {
        if (INT_PATTERN.matcher(n).matches()) {
            if (n.length() < 10) {
                return Integer.valueOf(n);
            }
            return Long.valueOf(n);
        }
        return Double.valueOf(n);
    }

    public static Object unmarshal(AttributeValue av) {
        return switch (av.type()) {
            case B      -> av.b().asByteArray();
            case BOOL   -> av.bool();
            case BS     -> av.bs().stream()
                            .map(SdkBytes::asByteArray)
                            .collect(toList());
            case L      -> av.l().stream()
                            .map(AttributeValueConverter::unmarshal)
                            .collect(toList());
            case M      -> av.m().entrySet().stream()
                            .collect(toMap(
                                Entry::getKey,
                                n -> Optional.ofNullable(unmarshal(n.getValue()))
                            ));
            case N      -> parseNumber(av.n());
            case NS     -> av.ns().stream()
                            .map(AttributeValueConverter::parseNumber)
                            .collect(toSet());
            case NUL    -> null;
            case S      -> av.s();
            case SS     -> Set.copyOf(av.ss());
            case UNKNOWN_TO_SDK_VERSION ->
                throw new UnsupportedOperationException("Type not supported");
        };
    }

}
wz1wpwve

wz1wpwve5#

对于2.x SDK,使用DynamoDBEnhancedClient

DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .credentialsProvider(credentialsProvider)
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
     .dynamoDbClient(ddb)
     .build();
DynamoDbTable<Customer> custTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
Customer record = new Customer();
            record.setCustName("Fred Pink");
            record.setId("id110");
            record.setEmail("fredp@noserver.com");
// Put the customer data into an Amazon DynamoDB table.
custTable.putItem(record);

下面是一个完整的例子:https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/dynamodb/src/main/java/com/example/dynamodb/enhanced/EnhancedPutItem.java

相关问题