Java tutorial
/* * Copyright 1&1 Internet AG, https://github.com/1and1/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License 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 net.oneandone.troilus; import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.DataType; import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.TupleType; import com.datastax.driver.core.TypeCodec; import com.datastax.driver.core.UDTValue; import com.datastax.driver.core.UserType; import com.google.common.base.Optional; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * * @author Jason Westra - edited original * 12-12-2015: 3.x API changes. * 12-12-2015: New - serialize(), deserialize(), getCodecRegistry(), getMetadataCatalog() * */ class UDTValueMapper { private final ProtocolVersion protocolVersion; private final BeanMapper beanMapper; private final MetadataCatalog catalog; private final CodecRegistry codecRegistry = CodecRegistry.DEFAULT_INSTANCE; UDTValueMapper(ProtocolVersion protocolVersion, MetadataCatalog catalog, BeanMapper beanMapper) { this.protocolVersion = protocolVersion; this.catalog = catalog; this.beanMapper = beanMapper; } static boolean isBuildInType(DataType dataType) { if (dataType.isCollection()) { for (DataType type : dataType.getTypeArguments()) { if (!isBuildInType(type)) { return false; } } return true; } else { return DataType.allPrimitiveTypes().contains(dataType) || (TupleType.class.isAssignableFrom(dataType.getClass())); } } /** * @param datatype the db datatype * @param udtValue the udt value * @param fieldtype1 the field 1 type * @param fieldtype2 the field 2 type * @param fieldname the fieldname * @return the mapped value or <code>null</code> */ public <T> Object fromUdtValue(DataType datatype, UDTValue udtValue, Class<?> fieldtype1, Class<?> fieldtype2, String fieldname) { CodecRegistry codecRegistry = getCodecRegistry(); // build-in type if (isBuildInType(datatype)) { TypeCodec<T> typeCodec = codecRegistry.codecFor(datatype); return typeCodec.deserialize(udtValue.getBytesUnsafe(fieldname), protocolVersion); // jwestra: 3.x API change // return datatype.deserialize(udtValue.getBytesUnsafe(fieldname), protocolVersion); // udt collection } else if (datatype.isCollection()) { //Class<?> type = datatype.getName().asJavaClass(); // set if (DataType.Name.SET == datatype.getName()) { // jwestra: 3.x API change //if (Set.class.isAssignableFrom(type)) { // return fromUdtValues(datatype.getTypeArguments().get(0), // ImmutableSet.copyOf(udtValue.getSet(fieldname, UDTValue.class)), // fieldtype1); // New API passes fieldtype2, which is the elements class return fromUdtValues(datatype.getTypeArguments().get(0), ImmutableSet.copyOf(udtValue.getSet(fieldname, UDTValue.class)), fieldtype2); // list } else if (DataType.Name.LIST == datatype.getName()) { // jwestra: 3.x API change //} else if (List.class.isAssignableFrom(type)) { // return fromUdtValues(datatype.getTypeArguments().get(0), // ImmutableList.copyOf(udtValue.getList(fieldname, UDTValue.class)), // fieldtype1); // New API passes fieldtype2, which is the elements class return fromUdtValues(datatype.getTypeArguments().get(0), ImmutableList.copyOf(udtValue.getList(fieldname, UDTValue.class)), fieldtype2); // map } else { if (isBuildInType(datatype.getTypeArguments().get(0))) { return fromUdtValues(datatype.getTypeArguments().get(0), datatype.getTypeArguments().get(1), ImmutableMap .<Object, Object>copyOf(udtValue.getMap(fieldname, fieldtype1, UDTValue.class)), fieldtype1, fieldtype2); } else if (isBuildInType(datatype.getTypeArguments().get(1))) { return fromUdtValues(datatype.getTypeArguments().get(0), datatype.getTypeArguments().get(1), ImmutableMap .<Object, Object>copyOf(udtValue.getMap(fieldname, UDTValue.class, fieldtype2)), fieldtype1, fieldtype2); } else { return fromUdtValues(datatype.getTypeArguments().get(0), datatype.getTypeArguments().get(1), ImmutableMap.<Object, Object>copyOf( udtValue.getMap(fieldname, UDTValue.class, UDTValue.class)), fieldtype1, fieldtype2); } } // udt } else { return fromUdtValue(datatype, udtValue, fieldtype1); } } public <T> T fromUdtValue(final DataType datatype, final UDTValue udtValue, Class<T> type) { PropertiesSource propsSource = new PropertiesSource() { @Override public <E> Optional<E> read(String name, Class<?> clazz1) { return read(name, clazz1, Object.class); } @SuppressWarnings("unchecked") @Override public <E> Optional<E> read(String name, Class<?> clazz1, Class<?> clazz2) { return Optional.fromNullable( (E) fromUdtValue(((UserType) datatype).getFieldType(name), udtValue, clazz1, clazz2, name)); } }; return beanMapper.fromValues(type, propsSource, ImmutableSet.<String>of()); } public <T> ImmutableSet<T> fromUdtValues(final DataType datatype, ImmutableSet<UDTValue> udtValues, Class<T> type) { return ImmutableSet.copyOf(fromUdtValues(datatype, (ImmutableCollection<UDTValue>) udtValues, type)); } public <T> ImmutableList<T> fromUdtValues(final DataType datatype, ImmutableList<UDTValue> udtValues, Class<T> type) { return fromUdtValues(datatype, (ImmutableCollection<UDTValue>) udtValues, type); } private <T> ImmutableList<T> fromUdtValues(final DataType datatype, ImmutableCollection<UDTValue> udtValues, Class<T> type) { List<T> elements = Lists.newArrayList(); for (UDTValue elementUdtValue : udtValues) { final UDTValue elementUdtVal = elementUdtValue; PropertiesSource propsSource = new PropertiesSource() { @Override public <E> Optional<E> read(String name, Class<?> clazz1) { return read(name, clazz1, Object.class); } @SuppressWarnings("unchecked") @Override public <E> Optional<E> read(String name, Class<?> clazz1, Class<?> clazz2) { return Optional.fromNullable((E) fromUdtValue(((UserType) datatype).getFieldType(name), elementUdtVal, clazz1, clazz2, name)); } }; T element = beanMapper.fromValues(type, propsSource, ImmutableSet.<String>of()); elements.add(element); } return ImmutableList.copyOf(elements); } @SuppressWarnings("unchecked") public <K, V> ImmutableMap<K, V> fromUdtValues(final DataType keyDatatype, final DataType valueDatatype, ImmutableMap<?, ?> udtValues, Class<K> keystype, Class<V> valuesType) { Map<K, V> elements = Maps.newHashMap(); for (Entry<?, ?> entry : udtValues.entrySet()) { K keyElement; if (keystype.isAssignableFrom(entry.getKey().getClass())) { keyElement = (K) entry.getKey(); } else { final UDTValue keyUdtValue = (UDTValue) entry.getKey(); PropertiesSource propsSource = new PropertiesSource() { @Override public <E> Optional<E> read(String name, Class<?> clazz1) { return read(name, clazz1, Object.class); } @Override public <T> Optional<T> read(String name, Class<?> clazz1, Class<?> clazz2) { return Optional.fromNullable((T) fromUdtValue(((UserType) keyDatatype).getFieldType(name), keyUdtValue, clazz1, clazz2, name)); } }; keyElement = beanMapper.fromValues(keystype, propsSource, ImmutableSet.<String>of()); } V valueElement; if (valuesType.isAssignableFrom(entry.getValue().getClass())) { valueElement = (V) entry.getValue(); } else { final UDTValue valueUdtValue = (UDTValue) entry.getValue(); PropertiesSource propsSource = new PropertiesSource() { @Override public <E> Optional<E> read(String name, Class<?> clazz1) { return read(name, clazz1, Object.class); } @Override public <T> Optional<T> read(String name, Class<?> clazz1, Class<?> clazz2) { return Optional.fromNullable((T) fromUdtValue(((UserType) valueDatatype).getFieldType(name), valueUdtValue, clazz1, clazz2, name)); } }; valueElement = beanMapper.fromValues(valuesType, propsSource, ImmutableSet.<String>of()); } elements.put(keyElement, valueElement); } return ImmutableMap.copyOf(elements); } @SuppressWarnings("unchecked") public Object toUdtValue(Tablename tablename, MetadataCatalog catalog, DataType datatype, Object value) { // build-in type (will not be converted) if (isBuildInType(datatype)) { return value; // udt collection } else if (datatype.isCollection()) { // set if (DataType.Name.SET == datatype.getName()) { // jwestra: 3.x API change //if (Set.class.isAssignableFrom(datatype.getName().asJavaClass())) { DataType elementDataType = datatype.getTypeArguments().get(0); Set<Object> udt = Sets.newHashSet(); if (value != null) { for (Object element : (Set<Object>) value) { udt.add(toUdtValue(tablename, catalog, elementDataType, element)); } } return ImmutableSet.copyOf(udt); // list } else if (DataType.Name.LIST == datatype.getName()) { // jwestra: 3.x API change // } else if (List.class.isAssignableFrom(datatype.getName().asJavaClass())) { DataType elementDataType = datatype.getTypeArguments().get(0); List<Object> udt = Lists.newArrayList(); if (value != null) { for (Object element : (List<Object>) value) { udt.add(toUdtValue(tablename, catalog, elementDataType, element)); } } return ImmutableList.copyOf(udt); // map } else { DataType keyDataType = datatype.getTypeArguments().get(0); DataType valueDataType = datatype.getTypeArguments().get(1); Map<Object, Object> udt = Maps.newHashMap(); if (value != null) { for (Entry<Object, Object> entry : ((Map<Object, Object>) value).entrySet()) { udt.put(toUdtValue(tablename, catalog, keyDataType, entry.getKey()), toUdtValue(tablename, catalog, valueDataType, entry.getValue())); } } return ImmutableMap.copyOf(udt); } // udt } else { if (value == null) { return value; } else { UserType usertype = catalog.getUserType(tablename, ((UserType) datatype).getTypeName()); UDTValue udtValue = usertype.newValue(); for (Entry<String, Optional<Object>> entry : beanMapper.toValues(value, ImmutableSet.<String>of()) .entrySet()) { if (!entry.getValue().isPresent()) { return null; } DataType fieldType = usertype.getFieldType(entry.getKey()); Object vl = entry.getValue().get(); if (!isBuildInType(usertype.getFieldType(entry.getKey()))) { vl = toUdtValue(tablename, catalog, fieldType, vl); } String key = entry.getKey(); udtValue.setBytesUnsafe(key, serialize(fieldType, vl)); // fieldType. // udtValue.setBytesUnsafe(entry.getKey(), fieldType.serialize(vl, protocolVersion)); } return udtValue; } } } /** * @param tablename the table name * @param name the columnname * @param value the value * @return the mapped value */ Object toStatementValue(Tablename tablename, String name, Object value) { if (isNullOrEmpty(value)) { return null; } DataType dataType = catalog.getColumnMetadata(tablename, name).getType(); // build in if (UDTValueMapper.isBuildInType(dataType)) { // enum if (DataTypes.isTextDataType(dataType) && Enum.class.isAssignableFrom(value.getClass())) { return value.toString(); } // byte buffer (byte[]) if (dataType.equals(DataType.blob()) && byte[].class.isAssignableFrom(value.getClass())) { return ByteBuffer.wrap((byte[]) value); } return value; // udt } else { return toUdtValue(tablename, catalog, catalog.getColumnMetadata(tablename, name).getType(), value); } } /** * @param tablename the tablename * @param name the columnname * @param values the vlaues * @return the mapped values */ ImmutableList<Object> toStatementValues(Tablename tablename, String name, ImmutableList<Object> values) { List<Object> result = Lists.newArrayList(); for (Object value : values) { result.add(toStatementValue(tablename, name, value)); } return ImmutableList.copyOf(result); } private boolean isNullOrEmpty(Object value) { return (value == null) || (Collection.class.isAssignableFrom(value.getClass()) && ((Collection<?>) value).isEmpty()) || (Map.class.isAssignableFrom(value.getClass()) && ((Map<?, ?>) value).isEmpty()); } /////////////////////////////////////////////////////////////////////////////////// // // NEW // /////////////////////////////////////////////////////////////////////////////////// /** * Get the CodecRegistry this uses to serialize/deserialize * @return the codecRegistry */ public CodecRegistry getCodecRegistry() { return this.codecRegistry; } /** * Get the metadata catalog this uses * @return the metadata catalog */ public MetadataCatalog getMetadataCatalog() { return this.catalog; } /** * Serialize a field using the data type passed. * @param dataType * @param value * @return */ @SuppressWarnings("unchecked") public <T> ByteBuffer serialize(DataType dataType, Object value) { CodecRegistry codecRegistry = getCodecRegistry(); TypeCodec<T> typeCodec = codecRegistry.codecFor(dataType); return typeCodec.serialize((T) value, protocolVersion); } /** * Serialize a field using the Codec for the value itself * @param value * @return */ public <T> ByteBuffer serialize(T value) { CodecRegistry codecRegistry = getCodecRegistry(); TypeCodec<T> typeCodec = codecRegistry.codecFor(value); return typeCodec.serialize((T) value, protocolVersion); } /** * jwestra: 3.x API change * deserialize a single field in a UDTValue map * @param dataType * @param udtValue * @param fieldname * @return */ public <T> T deserialize(DataType dataType, UDTValue udtValue, String fieldname) { CodecRegistry codecRegistry = getCodecRegistry(); TypeCodec<T> typeCodec = codecRegistry.codecFor(dataType); return typeCodec.deserialize(udtValue.getBytesUnsafe(fieldname), protocolVersion); } /** * Deserialize a whole ByteBuffer into an object * @param dataType * @param byteBuffer * @return */ public <T> T deserialize(DataType dataType, ByteBuffer byteBuffer) { CodecRegistry codecRegistry = getCodecRegistry(); TypeCodec<T> typeCodec = codecRegistry.codecFor(dataType); return typeCodec.deserialize(byteBuffer, protocolVersion); } }