implement wrapper to replace Casser.pojo

This commit is contained in:
Albert Shift 2015-03-27 12:19:49 -07:00
parent 64d2d6fdd9
commit 5c88f2d4e4
11 changed files with 220 additions and 30 deletions

View file

@ -19,6 +19,7 @@ import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import casser.core.Instantiator; import casser.core.Instantiator;
import casser.core.WrapperInstantiator;
public interface CasserSettings { public interface CasserSettings {
@ -33,5 +34,7 @@ public interface CasserSettings {
Instantiator getDslInstantiator(); Instantiator getDslInstantiator();
Instantiator getPojoInstantiator(); Instantiator getPojoInstantiator();
WrapperInstantiator getWrapperInstantiator();
} }

View file

@ -19,8 +19,10 @@ import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import casser.core.Instantiator; import casser.core.Instantiator;
import casser.core.WrapperInstantiator;
import casser.core.reflect.ReflectionDslInstantiator; import casser.core.reflect.ReflectionDslInstantiator;
import casser.core.reflect.ReflectionPojoInstantiator; import casser.core.reflect.ReflectionPojoInstantiator;
import casser.core.reflect.ReflectionWrapperInstantiator;
import casser.mapping.convert.CamelCaseToUnderscoreConverter; import casser.mapping.convert.CamelCaseToUnderscoreConverter;
import casser.mapping.convert.MethodNameToPropertyConverter; import casser.mapping.convert.MethodNameToPropertyConverter;
@ -56,6 +58,9 @@ public class DefaultCasserSettings implements CasserSettings {
return ReflectionPojoInstantiator.INSTANCE; return ReflectionPojoInstantiator.INSTANCE;
} }
@Override
public WrapperInstantiator getWrapperInstantiator() {
return ReflectionWrapperInstantiator.INSTANCE;
}
} }

View file

@ -15,15 +15,12 @@
*/ */
package casser.core; package casser.core;
import java.lang.reflect.Proxy; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import casser.config.CasserSettings; import casser.config.CasserSettings;
import casser.config.DefaultCasserSettings; import casser.config.DefaultCasserSettings;
import casser.core.reflect.DslInvocationHandler;
import casser.core.reflect.PojoInvocationHandler;
import casser.mapping.convert.UDTValueWritable;
import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
@ -97,5 +94,13 @@ public final class Casser {
public static <E> E pojo(Class<E> iface, ClassLoader classLoader) { public static <E> E pojo(Class<E> iface, ClassLoader classLoader) {
return settings.getPojoInstantiator().instantiate(iface, classLoader); return settings.getPojoInstantiator().instantiate(iface, classLoader);
} }
public static <E> E wrap(Map<String, Object> map, Class<E> iface) {
return wrap(map, iface, iface.getClassLoader());
}
public static <E> E wrap(Map<String, Object> map, Class<E> iface, ClassLoader classLoader) {
return settings.getWrapperInstantiator().instantiate(map, iface, classLoader);
}
} }

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2015 Noorq, 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 casser.core;
import java.util.Map;
public interface WrapperInstantiator {
<E> E instantiate(Map<String, Object> map, Class<E> iface, ClassLoader classLoader);
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (C) 2015 Noorq, 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 casser.core.reflect;
import java.lang.reflect.Proxy;
import java.util.Map;
import casser.core.WrapperInstantiator;
import casser.mapping.MapExportable;
public enum ReflectionWrapperInstantiator implements WrapperInstantiator {
INSTANCE;
@Override
@SuppressWarnings("unchecked")
public <E> E instantiate(Map<String, Object> map, Class<E> iface,
ClassLoader classLoader) {
WrapperInvocationHandler<E> handler = new WrapperInvocationHandler<E>(map, iface);
E proxy = (E) Proxy.newProxyInstance(
classLoader,
new Class[] { iface, MapExportable.class },
handler);
return proxy;
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2015 Noorq, 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 casser.core.reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import casser.mapping.MapExportable;
import casser.support.CasserException;
public class WrapperInvocationHandler<E> implements InvocationHandler {
private final Map<String, Object> map;
private final Class<E> iface;
public WrapperInvocationHandler(Map<String, Object> map, Class<E> iface) {
this.map = map;
this.iface = iface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new CasserException("invalid getter method " + method);
}
String methodName = method.getName();
if ("toString".equals(methodName)) {
return "Wrapper:" + iface + ":" + map.toString();
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
return Collections.unmodifiableMap(map);
}
Object value = map.get(methodName);
if (value == null) {
Class<?> returnType = method.getReturnType();
if (returnType.isPrimitive()) {
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
if (type == null) {
throw new CasserException("unknown primitive type " + returnType);
}
return type.getDefaultValue();
}
}
return value;
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Noorq, 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 casser.mapping;
import java.util.Map;
public interface MapExportable {
public static final String TO_MAP_METHOD = "toMap";
Map<String, Object> toMap();
}

View file

@ -15,17 +15,14 @@
*/ */
package casser.test.unit.core.dsl; package casser.test.unit.core.dsl;
import casser.mapping.MapExportable;
import casser.mapping.Table; import casser.mapping.Table;
@Table @Table
public interface Account { public interface Account extends MapExportable {
String getId(); Long id();
void setId(String acc); boolean active();
boolean isActive();
void setActive(boolean a);
} }

View file

@ -29,12 +29,14 @@ public class DslTest {
System.out.println("account = " + account); System.out.println("account = " + account);
/*
try { try {
account.getId(); account.id();
} }
catch(DslPropertyException e) { catch(DslPropertyException e) {
System.out.println(e.getProperty()); System.out.println(e.getProperty());
} }
*/
} }

View file

@ -15,44 +15,52 @@
*/ */
package casser.test.unit.core.dsl; package casser.test.unit.core.dsl;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import casser.core.Casser; import casser.core.Casser;
import casser.support.CasserException; import casser.support.CasserException;
public class PojoTest { public class WrapperTest {
Account account = Casser.pojo(Account.class);
@Test @Test
public void testObject() throws Exception { public void testWrap() throws Exception {
Assert.assertNull(account.getId()); Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 123L);
map.put("active", Boolean.TRUE);
map.put("unknownField", "he-he");
account.setId("testAcc"); Account account = Casser.wrap(map, Account.class);
Assert.assertEquals("testAcc", account.getId()); Assert.assertEquals(Long.valueOf(123L), account.id());
Assert.assertTrue(account.active());
} }
@Test @Test
public void testPrimitive() throws Exception { public void testPrimitive() throws Exception {
Assert.assertFalse(account.isActive()); Map<String, Object> map = new HashMap<String, Object>();
account.setActive(true); map.put("id", 123L);
Assert.assertEquals(true, account.isActive());
Account account = Casser.wrap(map, Account.class);
Assert.assertFalse(account.active());
} }
@Test(expected=CasserException.class) @Test(expected=CasserException.class)
public void testWrongMethods() throws Exception { public void testWrongMethods() throws Exception {
Casser.pojo(WrongAccount.class); WrongAccount wrongAccount = Casser.wrap(new HashMap<String, Object>(), WrongAccount.class);
wrongAccount.id();
} }

View file

@ -17,6 +17,6 @@ package casser.test.unit.core.dsl;
public interface WrongAccount { public interface WrongAccount {
void getId(); void id();
} }