DATACASS-164: app & test code done
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package org.springframework.data.cassandra.repository.support;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.springframework.data.cassandra.repository.MapId;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MapIdFactory {
|
||||
|
||||
public static <T extends MapId> T id(Class<T> idInterface) {
|
||||
Assert.notNull(idInterface);
|
||||
return id(idInterface, idInterface.getClassLoader());
|
||||
}
|
||||
|
||||
public static <T extends MapId> T id(Class<T> idInterface, ClassLoader loader) {
|
||||
return (T) Proxy.newProxyInstance(loader, new Class<?>[] { idInterface }, new MapIdProxyDelegate(idInterface));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.springframework.data.cassandra.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.data.cassandra.repository.MapId;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
class MapIdProxyDelegate implements InvocationHandler {
|
||||
|
||||
static class Signature {
|
||||
String name;
|
||||
Class<?>[] argTypes;
|
||||
Class<?> returnType;
|
||||
|
||||
Signature(Method method, boolean includeReturnType) {
|
||||
this(method.getName(), method.getParameterTypes(), includeReturnType ? method.getReturnType() : null);
|
||||
}
|
||||
|
||||
Signature(String name, Class<?>[] argTypes, Class<?> returnType) {
|
||||
this.name = name;
|
||||
this.argTypes = argTypes;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Signature [name=" + name + ", argTypes=" + Arrays.toString(argTypes) + ", returnType=" + returnType + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == that) {
|
||||
return true;
|
||||
}
|
||||
if (!(that instanceof Signature)) {
|
||||
return false;
|
||||
}
|
||||
Signature that_ = (Signature) that;
|
||||
if (!this.name.equals(that_.name)) {
|
||||
return false;
|
||||
}
|
||||
if ((this.argTypes == null && that_.argTypes != null) || (this.argTypes != null && that_.argTypes == null)) {
|
||||
return false;
|
||||
}
|
||||
if (this.argTypes != null) {
|
||||
if (this.argTypes.length != that_.argTypes.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < this.argTypes.length; i++) {
|
||||
if (!this.argTypes[i].equals(that_.argTypes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.returnType == null) {
|
||||
return that_.returnType == null;
|
||||
}
|
||||
return this.returnType.equals(that_.returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ (argTypes != null ? argTypes.hashCode() : 0)
|
||||
^ (returnType != null ? returnType.hashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Signature[] MAP_ID_SIGNATURES;
|
||||
|
||||
static {
|
||||
Method[] mapIdMethods = MapId.class.getMethods();
|
||||
MAP_ID_SIGNATURES = new Signature[mapIdMethods.length];
|
||||
int i = 0;
|
||||
for (Method m : mapIdMethods) {
|
||||
MAP_ID_SIGNATURES[i++] = new Signature(m, true);
|
||||
}
|
||||
}
|
||||
|
||||
MapId delegate = new BasicMapId();
|
||||
Class<?> idInterface;
|
||||
|
||||
MapIdProxyDelegate(Class<?> idInterface) {
|
||||
this.idInterface = idInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (isMapIdMethod(method)) {
|
||||
return method.invoke(delegate, args);
|
||||
}
|
||||
|
||||
if (args != null && args.length > 1) {
|
||||
throw new IllegalArgumentException(String.format("Method [%s] on interface [%s] must take zero or one argument",
|
||||
method, idInterface));
|
||||
}
|
||||
boolean isSetter = args != null && args.length == 1;
|
||||
String name = method.getName();
|
||||
|
||||
if (isSetter) {
|
||||
handleSetter(name, args[0]);
|
||||
return void.class.equals(method.getReturnType()) ? null : proxy;
|
||||
}
|
||||
|
||||
return handleGetter(name);
|
||||
}
|
||||
|
||||
private boolean isMapIdMethod(Method method) {
|
||||
for (Signature mapIdSignature : MAP_ID_SIGNATURES) {
|
||||
if (mapIdSignature.equals(new Signature(method, true))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Serializable handleGetter(String name) {
|
||||
if (name.startsWith("get")) {
|
||||
if (name.length() == 3) {
|
||||
throw new IllegalArgumentException(String.format("Method [%s] on interface [%s] must be of form "
|
||||
+ "'<PropertyType> get<PropertyName>()' or " + "'<PropertyType> <propertyName>()'", name, idInterface));
|
||||
}
|
||||
name = StringUtils.uncapitalize(name.substring(3));
|
||||
}
|
||||
|
||||
return delegate.get(name);
|
||||
}
|
||||
|
||||
private void handleSetter(String name, Object value) {
|
||||
int minLength = 1;
|
||||
boolean isSet = name.startsWith("set");
|
||||
boolean isWith = name.startsWith("with");
|
||||
minLength += isSet ? 3 : isWith ? 4 : 0;
|
||||
int length = name.length();
|
||||
if (isSet || isWith) {
|
||||
if (length < minLength) {
|
||||
throw new IllegalArgumentException(String.format("Method [%s] on interface [%s] must be of form "
|
||||
+ "'<IdType|void> set<PropertyName>(<PropertyType>)', "
|
||||
+ "'<IdType|void> with<PropertyName>(<PropertyType>)' or "
|
||||
+ "'<IdType|void> <propertyName>(<PropertyType>)'", name, idInterface));
|
||||
}
|
||||
name = StringUtils.uncapitalize(name.substring(minLength - 1));
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
delegate.put(name, null);
|
||||
return;
|
||||
}
|
||||
if (!(value instanceof Serializable)) {
|
||||
throw new IllegalArgumentException(String.format("Given object [%s] must implement %s", value,
|
||||
Serializable.class.getName()));
|
||||
}
|
||||
delegate.put(name, (Serializable) value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package org.springframework.data.cassandra.test.integration.mapping.mapid.proxy;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.springframework.data.cassandra.repository.support.MapIdFactory.id;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.data.cassandra.mapping.Column;
|
||||
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
import org.springframework.data.cassandra.repository.MapId;
|
||||
import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest;
|
||||
import org.springframework.data.cassandra.test.integration.support.IntegrationTestConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class CassandraTemplateMapIdProxyDelegateIntegrationTest extends
|
||||
AbstractSpringDataEmbeddedCassandraIntegrationTest {
|
||||
|
||||
@Configuration
|
||||
public static class Config extends IntegrationTestConfig {
|
||||
|
||||
@Override
|
||||
public String[] getEntityBasePackages() {
|
||||
return new String[] { SinglePkc.class.getPackage().getName() };
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
CassandraOperations t;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
assertNotNull(t);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSinglePkc() {
|
||||
|
||||
// insert
|
||||
SinglePkc inserted = new SinglePkc(uuid());
|
||||
inserted.setValue(uuid());
|
||||
SinglePkc saved = t.insert(inserted);
|
||||
assertSame(saved, inserted);
|
||||
|
||||
// select
|
||||
SinglePkcId id = id(SinglePkcId.class).key(saved.getKey());
|
||||
SinglePkc selected = t.selectOneById(SinglePkc.class, id);
|
||||
assertNotSame(selected, saved);
|
||||
assertEquals(saved.getKey(), selected.getKey());
|
||||
assertEquals(saved.getValue(), selected.getValue());
|
||||
|
||||
// update
|
||||
selected.setValue(uuid());
|
||||
SinglePkc updated = t.update(selected);
|
||||
assertSame(updated, selected);
|
||||
|
||||
selected = t.selectOneById(SinglePkc.class, id);
|
||||
assertNotSame(selected, updated);
|
||||
assertEquals(updated.getValue(), selected.getValue());
|
||||
|
||||
// delete
|
||||
t.delete(selected);
|
||||
assertNull(t.selectOneById(SinglePkc.class, id));
|
||||
}
|
||||
|
||||
public interface SinglePkcId extends MapId {
|
||||
SinglePkcId key(String key);
|
||||
|
||||
String key();
|
||||
}
|
||||
|
||||
@Table
|
||||
public static class SinglePkc {
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
|
||||
String key;
|
||||
|
||||
@Column
|
||||
String value;
|
||||
|
||||
/**
|
||||
* @deprecated for persistence use only
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unused")
|
||||
private SinglePkc() {}
|
||||
|
||||
public SinglePkc(String key) {
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPkc() {
|
||||
|
||||
// insert
|
||||
MultiPkc inserted = new MultiPkc(uuid(), uuid());
|
||||
inserted.setValue(uuid());
|
||||
MultiPkc saved = t.insert(inserted);
|
||||
assertSame(saved, inserted);
|
||||
|
||||
// select
|
||||
MultiPkcId id = id(MultiPkcId.class).key0(saved.getKey0()).key1(saved.getKey1());
|
||||
MultiPkc selected = t.selectOneById(MultiPkc.class, id);
|
||||
assertNotSame(selected, saved);
|
||||
assertEquals(saved.getKey0(), selected.getKey0());
|
||||
assertEquals(saved.getKey1(), selected.getKey1());
|
||||
assertEquals(saved.getValue(), selected.getValue());
|
||||
|
||||
// update
|
||||
selected.setValue(uuid());
|
||||
MultiPkc updated = t.update(selected);
|
||||
assertSame(updated, selected);
|
||||
|
||||
selected = t.selectOneById(MultiPkc.class, id);
|
||||
assertNotSame(selected, updated);
|
||||
assertEquals(updated.getValue(), selected.getValue());
|
||||
|
||||
// delete
|
||||
t.delete(selected);
|
||||
assertNull(t.selectOneById(MultiPkc.class, id));
|
||||
}
|
||||
|
||||
public interface MultiPkcId extends MapId {
|
||||
MultiPkcId key0(String key0);
|
||||
|
||||
String key0();
|
||||
|
||||
MultiPkcId key1(String key1);
|
||||
|
||||
String key1();
|
||||
}
|
||||
|
||||
@Table
|
||||
public static class MultiPkc {
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
|
||||
String key0;
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 1)
|
||||
String key1;
|
||||
|
||||
@Column
|
||||
String value;
|
||||
|
||||
/**
|
||||
* @deprecated for persistence use only
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unused")
|
||||
private MultiPkc() {}
|
||||
|
||||
public MultiPkc(String key0, String key1) {
|
||||
setKey0(key0);
|
||||
setKey1(key1);
|
||||
}
|
||||
|
||||
public String getKey0() {
|
||||
return key0;
|
||||
}
|
||||
|
||||
public void setKey0(String key0) {
|
||||
this.key0 = key0;
|
||||
}
|
||||
|
||||
public String getKey1() {
|
||||
return key1;
|
||||
}
|
||||
|
||||
public void setKey1(String key1) {
|
||||
this.key1 = key1;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.springframework.data.cassandra.test.unit.mapidfactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.springframework.data.cassandra.repository.support.MapIdFactory.id;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.cassandra.repository.MapId;
|
||||
|
||||
public class MapIdFactoryTest {
|
||||
|
||||
static interface MyId extends MapId {
|
||||
MyId string(String s);
|
||||
|
||||
void setString(String s);
|
||||
|
||||
MyId withString(String s);
|
||||
|
||||
String string();
|
||||
|
||||
String getString();
|
||||
|
||||
MyId number(Integer i);
|
||||
|
||||
void setNumber(Integer i);
|
||||
|
||||
Integer number();
|
||||
|
||||
Integer getNumber();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Random r = new Random();
|
||||
String s = "" + r.nextInt();
|
||||
Integer i = new Integer(r.nextInt());
|
||||
|
||||
MyId id = id(MyId.class);
|
||||
|
||||
assertNull(id.string());
|
||||
assertNull(id.number());
|
||||
assertNull(id.getString());
|
||||
assertNull(id.getNumber());
|
||||
|
||||
id.setNumber(i);
|
||||
assertEquals(i, id.getNumber());
|
||||
assertEquals(i, id.number());
|
||||
assertEquals(i, id.get("number"));
|
||||
|
||||
MyId returned = null;
|
||||
|
||||
returned = id.number(i = r.nextInt());
|
||||
assertSame(returned, id);
|
||||
assertEquals(i, id.getNumber());
|
||||
assertEquals(i, id.number());
|
||||
assertEquals(i, id.get("number"));
|
||||
|
||||
id.put("number", i = r.nextInt());
|
||||
assertEquals(i, id.getNumber());
|
||||
assertEquals(i, id.number());
|
||||
assertEquals(i, id.get("number"));
|
||||
|
||||
id.setString(s);
|
||||
assertEquals(s, id.getString());
|
||||
assertEquals(s, id.string());
|
||||
assertEquals(s, id.get("string"));
|
||||
|
||||
returned = id.string(s = "" + r.nextInt());
|
||||
assertSame(returned, id);
|
||||
assertEquals(s, id.getString());
|
||||
assertEquals(s, id.string());
|
||||
assertEquals(s, id.get("string"));
|
||||
|
||||
returned = id.withString(s = "" + r.nextInt());
|
||||
assertSame(returned, id);
|
||||
assertEquals(s, id.getString());
|
||||
assertEquals(s, id.string());
|
||||
assertEquals(s, id.get("string"));
|
||||
|
||||
id.put("string", s = "" + r.nextInt());
|
||||
assertEquals(s, id.getString());
|
||||
assertEquals(s, id.string());
|
||||
assertEquals(s, id.get("string"));
|
||||
|
||||
id.setString(null);
|
||||
assertNull(id.getString());
|
||||
assertNull(id.string());
|
||||
assertNull(id.get("string"));
|
||||
|
||||
id.setNumber(null);
|
||||
assertNull(id.getNumber());
|
||||
assertNull(id.number());
|
||||
assertNull(id.get("number"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user