/*
* Copyright 2016-2017 the original author or authors.
*
* 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 org.springframework.data.cassandra.repository.conversion;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cassandra.core.cql.CqlIdentifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraCustomConversions;
import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.mapping.SimpleUserTypeResolver;
import org.springframework.data.cassandra.mapping.UserTypeResolver;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest;
import org.springframework.data.cassandra.test.integration.support.IntegrationTestConfig;
import org.springframework.data.convert.CustomConversions;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test support for query method parameter type conversion.
*
* @author Mark Paluch
*/
abstract class ParameterConversionTestSupport extends AbstractSpringDataEmbeddedCassandraIntegrationTest {
@Configuration
@EnableCassandraRepositories(considerNestedRepositories = true)
public static class Config extends IntegrationTestConfig {
@Override
public String[] getEntityBasePackages() {
return new String[] { Contact.class.getPackage().getName() };
}
@Override
public SchemaAction getSchemaAction() {
return SchemaAction.RECREATE_DROP_UNUSED;
}
@Override
public CassandraSessionFactoryBean session() throws ClassNotFoundException {
Cluster cluster = cluster().getObject();
Session session = cluster.connect(getKeyspaceName());
session.execute("CREATE TYPE IF NOT EXISTS phone (number text);");
session.close();
return super.session();
}
@Override
public CustomConversions customConversions() {
return new CassandraCustomConversions(
Arrays.asList(AddressReadConverter.INSTANCE, AddressWriteConverter.INSTANCE, PhoneReadConverter.INSTANCE,
new PhoneWriteConverter(new SimpleUserTypeResolver(cluster().getObject(), getKeyspaceName()))));
}
}
@Autowired CassandraOperations template;
@Autowired CassandraAdminOperations adminOperations;
Contact walter, flynn;
@Before
public void before() {
deleteAllEntities();
template.getCqlOperations().execute("CREATE INDEX IF NOT EXISTS contact_address ON contact (address);");
template.getCqlOperations().execute("CREATE INDEX IF NOT EXISTS contact_addresses ON contact (addresses);");
template.getCqlOperations().execute("CREATE INDEX IF NOT EXISTS contact_main_phones ON contact (mainphone);");
template.getCqlOperations()
.execute("CREATE INDEX IF NOT EXISTS contact_alternative_phones ON contact (alternativephones);");
walter = new Contact("Walter");
walter.setAddress(new Address("Albuquerque", "USA"));
walter.setAddresses(Arrays.asList(new Address("Albuquerque", "USA"), new Address("New Hampshire", "USA"),
new Address("Grocery Store", "Mexico")));
Phone phone = new Phone();
phone.setNumber("(505) 555-1258");
Phone alternative = new Phone();
alternative.setNumber("505-842-4205");
walter.setMainPhone(phone);
walter.setAlternativePhones(Collections.singletonList(alternative));
flynn = new Contact("Flynn");
flynn.setAddress(new Address("Albuquerque", "USA"));
flynn.setAddresses(Collections.singletonList(new Address("Albuquerque", "USA")));
template.insert(walter);
template.insert(flynn);
}
/**
* @author Mark Paluch
*/
enum AddressWriteConverter implements Converter<Address, String> {
INSTANCE;
public String convert(Address source) {
try {
return new ObjectMapper().writeValueAsString(source);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
/**
* @author Mark Paluch
*/
private enum PhoneReadConverter implements Converter<UDTValue, Phone> {
INSTANCE;
public Phone convert(UDTValue source) {
Phone phone = new Phone();
phone.setNumber(source.getString("number"));
return phone;
}
}
/**
* @author Mark Paluch
*/
private static class PhoneWriteConverter implements Converter<Phone, UDTValue> {
private UserTypeResolver userTypeResolver;
PhoneWriteConverter(UserTypeResolver userTypeResolver) {
this.userTypeResolver = userTypeResolver;
}
public UDTValue convert(Phone source) {
UserType userType = userTypeResolver.resolveType(CqlIdentifier.cqlId("phone"));
UDTValue udtValue = userType.newValue();
udtValue.setString("number", source.getNumber());
return udtValue;
}
}
/**
* @author Mark Paluch
*/
private enum AddressReadConverter implements Converter<String, Address> {
INSTANCE;
public Address convert(String source) {
if (StringUtils.hasText(source)) {
try {
return new ObjectMapper().readValue(source, Address.class);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return null;
}
}
}