/*
* Copyright (C) 2012-2015 DataStax Inc.
*
* 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 com.datastax.driver.core;
import com.datastax.driver.core.exceptions.InvalidTypeException;
import org.testng.annotations.Test;
import java.nio.ByteBuffer;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test an edge case where the user register 2 codecs for the same Java type (here, String).
* SimpleStatements become almost unusable in these cases, but we are adding tests
* to check that at least it is possible to use prepared statements in these situations.
*/
public class TypeCodecOverlappingJavaTypeIntegrationTest extends CCMTestsSupport {
private static final String insertQuery = "INSERT INTO \"myTable\" (c_int, l_int, c_text) VALUES (?, ?, ?)";
private static final String selectQuery = "SELECT c_int, l_int, c_text FROM \"myTable\" WHERE c_int = ?";
@Override
public void onTestContextInitialized() {
execute(
"CREATE TABLE \"myTable\" ("
+ "c_int int PRIMARY KEY, "
+ "l_int list<int>, "
+ "c_text text "
+ ")"
);
}
public Cluster.Builder createClusterBuilder() {
return Cluster.builder().withCodecRegistry(
new CodecRegistry().register(new IntToStringCodec())
);
}
@Test(groups = "short")
public void should_use_custom_codecs_with_prepared_statements() {
PreparedStatement ps = session().prepare(insertQuery);
session().execute(
ps.bind()
.setInt(0, 42)
.setList(1, newArrayList(42))
.setString(2, "42") // here we have the CQL type so VarcharCodec will be used even if IntToStringCodec accepts it
);
session().execute(
ps.bind()
.setString(0, "42")
.setList(1, newArrayList("42"), String.class)
.setString(2, "42") // here we have the CQL type so VarcharCodec will be used even if IntToStringCodec accepts it
);
ps = session().prepare(selectQuery);
assertRow(session().execute(ps.bind().setInt(0, 42)).one());
assertRow(session().execute(ps.bind().setString(0, "42")).one());
}
private void assertRow(Row row) {
assertThat(row.getInt(0)).isEqualTo(42);
assertThat(row.getObject(0)).isEqualTo(42); // uses the default codec
assertThat(row.get(0, Integer.class)).isEqualTo(42);
assertThat(row.get(0, String.class)).isEqualTo("42");
assertThat(row.getList(1, Integer.class)).isEqualTo(newArrayList(42));
assertThat(row.getList(1, String.class)).isEqualTo(newArrayList("42"));
assertThat(row.getObject(1)).isEqualTo(newArrayList(42)); // uses the default codec
assertThat(row.get(1, TypeTokens.listOf(Integer.class))).isEqualTo(newArrayList(42));
assertThat(row.get(1, TypeTokens.listOf(String.class))).isEqualTo(newArrayList("42"));
}
private class IntToStringCodec extends TypeCodec<String> {
protected IntToStringCodec() {
super(DataType.cint(), String.class);
}
@Override
public ByteBuffer serialize(String value, ProtocolVersion protocolVersion) throws InvalidTypeException {
return TypeCodec.cint().serialize(value == null ? null : Integer.parseInt(value), protocolVersion);
}
@Override
public String deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) throws InvalidTypeException {
Integer i = TypeCodec.cint().deserialize(bytes, protocolVersion);
return i == null ? null : Integer.toString(i);
}
@Override
public String parse(String value) throws InvalidTypeException {
return value;
}
@Override
public String format(String value) throws InvalidTypeException {
return value;
}
@Override
public boolean accepts(Object value) {
return value instanceof String && ((String) value).matches("\\d+");
}
}
}