All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.dynamodbv2.document.ItemUtils Maven / Gradle / Ivy

Go to download

The AWS Java SDK for Amazon DynamoDB module holds the client classes that are used for communicating with Amazon DynamoDB Service

There is a newer version: 1.12.765
Show newest version
/*
 * Copyright 2012-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
 * the License. A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 */
package com.amazonaws.services.dynamodbv2.document;

import static com.amazonaws.util.BinaryUtils.copyAllBytesFrom;

import com.amazonaws.services.dynamodbv2.document.internal.Filter;
import com.amazonaws.services.dynamodbv2.document.internal.InternalUtils;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
import com.amazonaws.util.ValidationUtils;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Various utilities for manipulating {@link Item} and {@link AttributeValue} objects.
 */
public final class ItemUtils {

    private ItemUtils() {
    }

    /**
     * Returns an Item given the low level item information;
     * or null if the input is null;
     */
    public static Item toItem(Map item) {
        if (item == null) {
            return null;
        }
        return Item.fromMap(toSimpleMapValue(item));
    }

    /**
     * Returns a non-null list of Item's given the low level
     * list of item information.
     */
    public static List toItemList(List> items) {
        if (items == null) {
            return Collections.emptyList();
        }
        List result = new ArrayList(items.size());
        for (Map item : items) {
            result.add(toItem(item));
        }
        return result;
    }

    /**
     * Converts an Item into the low-level representation;
     * or null if the input is null.
     */
    public static Map toAttributeValues(Item item) {
        if (item == null)
            return null;
        // row with multiple attributes
        Map result = new LinkedHashMap();
        for (Map.Entry entry : item.attributes())
            result.put(entry.getKey(), toAttributeValue(entry.getValue()));
        return result;
    }

    /**
     * Converts a map of string to simple objects into the low-level
     * representation; or null if the input is null.
     */
    public static Map fromSimpleMap(
        Map map) {
        if (map == null)
            return null;
        // row with multiple attributes
        Map result = new LinkedHashMap();
        for (Map.Entry entry : map.entrySet())
            result.put(entry.getKey(), toAttributeValue(entry.getValue()));
        return result;
    }

    /**
     * Converts a list of AttributeUpdate into the low-level
     * representation; or null if the input is null.
     */
    public static Map toAttributeValueUpdate(
        List attributesToUpdate) {
        if (attributesToUpdate == null)
            return null;

        Map result = new LinkedHashMap();

        for (AttributeUpdate attribute : attributesToUpdate) {
            AttributeValueUpdate attributeToUpdate = new AttributeValueUpdate()
                .withAction(attribute.getAction());
            if (attribute.getValue() != null) {
                attributeToUpdate.withValue(toAttributeValue(attribute
                                                                 .getValue()));
            } else if (attribute.getAttributeValues() != null) {
                attributeToUpdate.withValue(toAttributeValue(attribute
                                                                 .getAttributeValues()));
            }
            result.put(attribute.getAttributeName(), attributeToUpdate);
        }

        return result;
    }

    /**
     * Converts a simple value into the low-level 
     * representation.
     *
     * @param value
     *            the given value which can be one of the followings:
     * 
    *
  • String
  • *
  • Set<String>
  • *
  • Number (including any subtypes and primitive types)
  • *
  • Set<Number>
  • *
  • byte[]
  • *
  • Set<byte[]>
  • *
  • ByteBuffer
  • *
  • Set<ByteBuffer>
  • *
  • Boolean or boolean
  • *
  • null
  • *
  • Map<String,T>, where T can be any type on this list but must not * induce any circular reference
  • *
  • List<T>, where T can be any type on this list but must not induce * any circular reference
  • *
* @return a non-null low level representation of the input object value * * @throws UnsupportedOperationException * if the input object type is not supported */ public static AttributeValue toAttributeValue(Object value) { AttributeValue result = new AttributeValue(); if (value == null) { return result.withNULL(Boolean.TRUE); } else if (value instanceof Boolean) { return result.withBOOL((Boolean)value); } else if (value instanceof String) { return result.withS((String) value); } else if (value instanceof BigDecimal) { BigDecimal bd = (BigDecimal) value; return result.withN(bd.toPlainString()); } else if (value instanceof Number) { return result.withN(value.toString()); } else if (value instanceof byte[]) { return result.withB(ByteBuffer.wrap((byte[]) value)); } else if (value instanceof ByteBuffer) { return result.withB((ByteBuffer) value); } else if (value instanceof Set) { // default to an empty string set if there is no element @SuppressWarnings("unchecked") Set set = (Set) value; if (set.size() == 0) { result.setSS(new LinkedHashSet()); return result; } Object element = set.iterator().next(); if (element instanceof String) { @SuppressWarnings("unchecked") Set ss = (Set) value; result.setSS(new ArrayList(ss)); } else if (element instanceof Number) { @SuppressWarnings("unchecked") Set in = (Set) value; List out = new ArrayList(set.size()); for (Number n : in) { BigDecimal bd = InternalUtils.toBigDecimal(n); out.add(bd.toPlainString()); } result.setNS(out); } else if (element instanceof byte[]) { @SuppressWarnings("unchecked") Set in = (Set) value; List out = new ArrayList(set.size()); for (byte[] buf : in) { out.add(ByteBuffer.wrap(buf)); } result.setBS(out); } else if (element instanceof ByteBuffer) { @SuppressWarnings("unchecked") Set bs = (Set) value; result.setBS(bs); } else { throw new UnsupportedOperationException("element type: " + element.getClass()); } } else if (value instanceof List) { @SuppressWarnings("unchecked") List in = (List) value; List out = new ArrayList(); for (Object v : in) { out.add(toAttributeValue(v)); } result.setL(out); } else if (value instanceof Map) { @SuppressWarnings("unchecked") Map in = (Map) value; if (in.size() > 0) { for (Map.Entry e : in.entrySet()) { result.addMEntry(e.getKey(), toAttributeValue(e.getValue())); } } else { // empty map result.setM(new LinkedHashMap()); } } else { throw new UnsupportedOperationException("value type: " + value.getClass()); } return result; } /** * Converts a list of low-level AttributeValue into a list of * simple values. Each value in the returned list can be one of the * followings: * *
    *
  • String
  • *
  • Set<String>
  • *
  • Number (including any subtypes and primitive types)
  • *
  • Set<Number>
  • *
  • byte[]
  • *
  • Set<byte[]>
  • *
  • ByteBuffer
  • *
  • Set<ByteBuffer>
  • *
  • Boolean or boolean
  • *
  • null
  • *
  • Map<String,T>, where T can be any type on this list but must not * induce any circular reference
  • *
  • List<T>, where T can be any type on this list but must not induce * any circular reference
  • *
*/ public static List toSimpleList(List attrValues) { if (attrValues == null) return null; List result = new ArrayList(attrValues.size()); for (AttributeValue attrValue : attrValues) { Object value = toSimpleValue(attrValue); result.add(value); } return result; } /** * Convenient method to convert a list of low-level * AttributeValue into a list of values of the same type T. * Each value in the returned list can be one of the followings: *
    *
  • String
  • *
  • Set<String>
  • *
  • Number (including any subtypes and primitive types)
  • *
  • Set<Number>
  • *
  • byte[]
  • *
  • Set<byte[]>
  • *
  • ByteBuffer
  • *
  • Set<ByteBuffer>
  • *
  • Boolean or boolean
  • *
  • null
  • *
  • Map<String,T>, where T can be any type on this list but must not * induce any circular reference
  • *
  • List<T>, where T can be any type on this list but must not induce * any circular reference
  • *
*/ public static List toSimpleListValue(List values) { if (values == null) { return null; } List result = new ArrayList(values.size()); for (AttributeValue v : values) { T t = toSimpleValue(v); result.add(t); } return result; } public static Map toSimpleMapValue( Map values) { if (values == null) { return null; } Map result = new LinkedHashMap(values.size()); for (Map.Entry entry : values.entrySet()) { T t = toSimpleValue(entry.getValue()); result.put(entry.getKey(), t); } return result; } /** * Returns the string representation of the given value; or null if the * value is null. For BigDecimal it will be the string * representation without an exponent field. */ public static String valToString(Object val) { if (val instanceof BigDecimal) { BigDecimal bd = (BigDecimal)val; return bd.toPlainString(); } if (val == null) return null; if (val instanceof String || val instanceof Boolean || val instanceof Number) return val.toString(); throw new IncompatibleTypeException("Cannot convert " + val.getClass() + " into a string"); } /** * Converts a low-level AttributeValue into a simple value, * which can be one of the followings: * *
    *
  • String
  • *
  • Set<String>
  • *
  • Number (including any subtypes and primitive types)
  • *
  • Set<Number>
  • *
  • byte[]
  • *
  • Set<byte[]>
  • *
  • ByteBuffer
  • *
  • Set<ByteBuffer>
  • *
  • Boolean or boolean
  • *
  • null
  • *
  • Map<String,T>, where T can be any type on this list but must not * induce any circular reference
  • *
  • List<T>, where T can be any type on this list but must not induce * any circular reference
  • *
* * @throws IllegalArgumentException * if an empty AttributeValue value is specified */ public static T toSimpleValue(AttributeValue value) { if (value == null) { return null; } if (Boolean.TRUE.equals(value.getNULL())) { return null; } else if (Boolean.FALSE.equals(value.getNULL())) { throw new UnsupportedOperationException("False-NULL is not supported in DynamoDB"); } else if (value.getBOOL() != null) { @SuppressWarnings("unchecked") T t = (T) value.getBOOL(); return t; } else if (value.getS() != null) { @SuppressWarnings("unchecked") T t = (T) value.getS(); return t; } else if (value.getN() != null) { @SuppressWarnings("unchecked") T t = (T) new BigDecimal(value.getN()); return t; } else if (value.getB() != null) { @SuppressWarnings("unchecked") T t = (T) copyAllBytesFrom(value.getB()); return t; } else if (value.getSS() != null) { @SuppressWarnings("unchecked") T t = (T) new LinkedHashSet(value.getSS()); return t; } else if (value.getNS() != null) { Set set = new LinkedHashSet(value.getNS().size()); for (String s : value.getNS()) { set.add(new BigDecimal(s)); } @SuppressWarnings("unchecked") T t = (T) set; return t; } else if (value.getBS() != null) { Set set = new LinkedHashSet(value.getBS().size()); for (ByteBuffer bb : value.getBS()) { set.add(copyAllBytesFrom(bb)); } @SuppressWarnings("unchecked") T t = (T) set; return t; } else if (value.getL() != null) { @SuppressWarnings("unchecked") T t = (T) toSimpleList(value.getL()); return t; } else if (value.getM() != null) { @SuppressWarnings("unchecked") T t = (T) toSimpleMapValue(value.getM()); return t; } else { throw new IllegalArgumentException( "Attribute value must not be empty: " + value); } } /** * Returns the minimum of the two input integers taking null into account. * Returns null if both integers are null. Otherwise, a null Integer is * treated as infinity. */ public static Integer minimum(Integer one, Integer two) { if (one == null) { return two; } else if (two == null) { return one; } else if (one < two) { return one; } else { return two; } } /** * Returns the low level representation of a collection of Expected. */ public static Map toExpectedAttributeValueMap( Collection expectedSet) { if (expectedSet == null) return null; Map expectedMap = new LinkedHashMap(); for (Expected expected : expectedSet) { final String attr = expected.getAttribute(); final Object[] values = expected.getValues(); ExpectedAttributeValue eav = new ExpectedAttributeValue(); if (values != null) { if (values.length > 0) { // convert from list of object values to list of AttributeValues AttributeValue[] avs = InternalUtils.toAttributeValues(values); eav.withAttributeValueList(avs); } else { throw new IllegalStateException("Bug!"); } } ComparisonOperator op = expected.getComparisonOperator(); if (op == null) { throw new IllegalArgumentException( "Comparison operator for attribute " + expected.getAttribute() + " must be specified"); } eav.withComparisonOperator(op); expectedMap.put(attr, eav); } if (expectedSet.size() != expectedMap.size()) throw new IllegalArgumentException("duplicates attribute names not allowed in input"); return Collections.unmodifiableMap(expectedMap); } /** * Returns the low level representation of a collection of Filter. */ public static Map toAttributeConditionMap(Collection> filters) { if (filters == null) return null; Map conditionMap = new LinkedHashMap(); for (Filter filter : filters) { final String attr = filter.getAttribute(); final Object[] values = filter.getValues(); Condition condition = new Condition(); if (values != null) { if (values.length > 0) { // convert from list of object values to list of AttributeValues AttributeValue[] avs = InternalUtils.toAttributeValues(values); condition.withAttributeValueList(avs); } else { throw new IllegalStateException("Bug!"); } } ComparisonOperator op = filter.getComparisonOperator(); if (op == null) { throw new IllegalArgumentException( "Comparison operator for attribute " + filter.getAttribute() + " must be specified"); } condition.withComparisonOperator(op); conditionMap.put(attr, condition); } if (filters.size() != conditionMap.size()) throw new IllegalArgumentException("duplicates attribute names not allowed in input"); return Collections.unmodifiableMap(conditionMap); } /** * Converts the input array of values into an array of low level * representation of those values. * * A value in the input array can be one of the followings: * *
    *
  • String
  • *
  • Set<String>
  • *
  • Number (including any subtypes and primitive types)
  • *
  • Set<Number>
  • *
  • byte[]
  • *
  • Set<byte[]>
  • *
  • ByteBuffer
  • *
  • Set<ByteBuffer>
  • *
  • Boolean or boolean
  • *
  • null
  • *
  • Map<String,T>, where T can be any type on this list but must not * induce any circular reference
  • *
  • List<T>, where T can be any type on this list but must not induce * any circular reference
  • *
*/ public static AttributeValue[] toAttributeValues(Object[] values) { AttributeValue[] attrValues = new AttributeValue[values.length]; for (int i=0; i < values.length; i++) attrValues[i] = InternalUtils.toAttributeValue(values[i]); return attrValues; } /** * Converts the specified primary key into the low-level representation. */ public static Map toAttributeValueMap( Collection primaryKey) { if (primaryKey == null) return null; Map keys = new LinkedHashMap(); for (KeyAttribute keyAttr : primaryKey) keys.put(keyAttr.getName(), InternalUtils.toAttributeValue(keyAttr.getValue())); return Collections.unmodifiableMap(keys); } /** * Converts the specified primary key into the low-level representation. */ public static Map toAttributeValueMap( PrimaryKey primaryKey) { if (primaryKey == null) return null; return toAttributeValueMap(primaryKey.getComponents()); } /** * Converts the specified primary key into the low-level representation. */ public static Map toAttributeValueMap( KeyAttribute ... primaryKey) { if (primaryKey == null) return null; return toAttributeValueMap(Arrays.asList(primaryKey)); } /** * Converts a number into BigDecimal representation. */ public static BigDecimal toBigDecimal(Number n) { if (n instanceof BigDecimal) return (BigDecimal)n; return new BigDecimal(n.toString()); } public static Set toBigDecimalSet(Number ... val) { Set set = new LinkedHashSet(val.length); for (Number n: val) set.add(InternalUtils.toBigDecimal(n)); return set; } public static Set toBigDecimalSet(Set vals) { Set set = new LinkedHashSet(vals.size()); for (Number n: vals) set.add(InternalUtils.toBigDecimal(n)); return set; } public static void checkInvalidAttrName(String attrName) { if (attrName == null || attrName.trim().length() == 0) throw new IllegalArgumentException("Attribute name must not be null or empty"); } public static void checkInvalidAttribute(String attrName, Object val) { checkInvalidAttrName(attrName); ValidationUtils.assertNotNull(val, attrName); } }