deltaspike-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject [04/11] DELTASPIKE-60 Data module initial import
Date Thu, 27 Jun 2013 08:39:04 GMT
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Properties.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Properties.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Properties.java
new file mode 100644
index 0000000..ee5f495
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Properties.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+ * Utility class for working with JavaBean style properties
+ *
+ * @author Pete Muir
+ * @author Shane Bryzak
+ * @see Property
+ */
+public class Properties
+{
+
+    private Properties()
+    {
+    }
+
+    /**
+     * Create a JavaBean style property from the field
+     *
+     * @param <V>
+     * @param field
+     * @return
+     */
+    public static <V> FieldProperty<V> createProperty(Field field)
+    {
+        return new FieldPropertyImpl<V>(field);
+    }
+
+    /**
+     * Create a JavaBean style property from the specified method
+     *
+     * @param <V>
+     * @param method
+     * @return
+     * @throws IllegalArgumentException
+     *             if the method does not match JavaBean conventions
+     * @see http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html
+     */
+    public static <V> MethodProperty<V> createProperty(Method method)
+    {
+        return new MethodPropertyImpl<V>(method);
+    }
+
+    /**
+     * Create a JavaBean style property from the specified member
+     *
+     * @param <V>
+     * @param member
+     * @return
+     * @throws IllegalArgumentException
+     *             if the method does not match JavaBean conventions
+     * @see http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html
+     */
+    public static <V> Property<V> createProperty(Member member)
+    {
+        if (member instanceof Method)
+        {
+            return new MethodPropertyImpl<V>(Method.class.cast(member));
+        }
+        else if (member instanceof Field)
+        {
+            return new FieldPropertyImpl<V>(Field.class.cast(member));
+        }
+        else
+        {
+            throw new IllegalArgumentException("Cannot make a property of " + member
+                    + " - it is neither a method or a field");
+        }
+    }
+
+    /**
+     * Indicates whether this method is a valid property method.
+     */
+    public static <V> boolean isProperty(Method method)
+    {
+        try
+        {
+            new MethodPropertyImpl<V>(method);
+            return true;
+        }
+        catch (IllegalArgumentException e)
+        {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Property.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Property.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Property.java
new file mode 100644
index 0000000..eeb29d9
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Property.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Member;
+import java.lang.reflect.Type;
+
+/**
+ * A representation of a JavaBean style property
+ *
+ * @param <V>
+ *            the type of the properties value
+ * @author Pete Muir
+ * @author Shane Bryzak
+ * @see Properties
+ */
+public interface Property<V>
+{
+    /**
+     * Returns the name of the property. If the property is a field, then the field name is returned. Otherwise, if the
+     * property is a method, then the name that is returned is the getter method name without the "get" or "is" prefix,
+     * and a lower case first letter.
+     *
+     * @return The name of the property
+     */
+    String getName();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Type getBaseType();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Class<V> getJavaClass();
+
+    /**
+     * Get the element responsible for retrieving the property value
+     *
+     * @return
+     */
+    AnnotatedElement getAnnotatedElement();
+
+    /**
+     * Get the member responsible for retrieving the property value
+     *
+     * @return
+     */
+    Member getMember();
+
+    /**
+     * Returns the property value for the specified bean. The property to be returned is either a field or getter
+     * method.
+     *
+     * @param bean
+     *            The bean to read the property from
+     * @return The property value
+     * @throws ClassCastException
+     *             if the value is not of the type V
+     */
+    V getValue(Object instance);
+
+    /**
+     * This method sets the property value for a specified bean to the specified value. The property to be set is either
+     * a field or setter method.
+     *
+     * @param bean
+     *            The bean containing the property to set
+     * @param value
+     *            The new property value
+     */
+    void setValue(Object instance, V value);
+
+    /**
+     * Returns the class that declares the property
+     *
+     * @return
+     */
+    Class<?> getDeclaringClass();
+
+    /**
+     * Indicates whether this is a read-only property
+     *
+     * @return
+     */
+    boolean isReadOnly();
+
+    /**
+     * Calls the setAccessible method on the underlying member(s).
+     * <p/>
+     * The operation should be performed within a {@link java.security.PrivilegedAction}
+     */
+    void setAccessible();
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Reflections.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Reflections.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Reflections.java
new file mode 100644
index 0000000..5d70465
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/Reflections.java
@@ -0,0 +1,514 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property;
+
+import java.beans.Introspector;
+import java.io.Serializable;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Utility class for working with JDK Reflection and also CDI's
+ * {@link javax.enterprise.inject.spi.Annotated} metadata.
+ *
+ * @author Stuart Douglas
+ * @author Pete Muir
+ */
+public class Reflections
+{
+    private Reflections()
+    {
+    }
+
+    /**
+     * <p>
+     * Perform a runtime cast. Similar to {@link Class#cast(Object)}, but useful when you do not have a {@link Class}
+     * object for type you wish to cast to.
+     * </p>
+     * <p/>
+     * <p>
+     * {@link Class#cast(Object)} should be used if possible
+     * </p>
+     *
+     * @param <T>
+     *            the type to cast to
+     * @param obj
+     *            the object to perform the cast on
+     * @return the casted object
+     * @throws ClassCastException
+     *             if the type T is not a subtype of the object
+     * @see Class#cast(Object)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj)
+    {
+        return (T) obj;
+    }
+
+    /**
+     * Determine if a method exists in a specified class hierarchy
+     *
+     * @param clazz
+     *            The class to search
+     * @param name
+     *            The name of the method
+     * @return true if a method is found, otherwise false
+     */
+    public static boolean methodExists(Class<?> clazz, String name)
+    {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass())
+        {
+            for (Method m : c.getDeclaredMethods())
+            {
+                if (m.getName().equals(name))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get all the declared methods on the class hierarchy. This <b>will</b> return overridden methods.
+     *
+     * @param clazz
+     *            The class to search
+     * @return the set of all declared methods or an empty set if there are none
+     */
+    public static Set<Method> getAllDeclaredMethods(Class<?> clazz)
+    {
+        HashSet<Method> methods = new HashSet<Method>();
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass())
+        {
+            for (Method a : c.getDeclaredMethods())
+            {
+                methods.add(a);
+            }
+        }
+        return methods;
+    }
+
+    /**
+     * Search the class hierarchy for a method with the given name and arguments. Will return the nearest match,
+     * starting with the class specified and searching up the hierarchy.
+     *
+     * @param clazz
+     *            The class to search
+     * @param name
+     *            The name of the method to search for
+     * @param args
+     *            The arguments of the method to search for
+     * @return The method found, or null if no method is found
+     */
+    public static Method findDeclaredMethod(Class<?> clazz, String name, Class<?>... args)
+    {
+        for (Class<?> c = clazz; c != null && c != Object.class; c = c.getSuperclass())
+        {
+            try
+            {
+                return c.getDeclaredMethod(name, args);
+            }
+            catch (NoSuchMethodException e)
+            {
+                // No-op, continue the search
+            }
+        }
+        return null;
+    }
+
+    private static String buildInvokeMethodErrorMessage(Method method, Object obj, Object... args)
+    {
+        StringBuilder message = new StringBuilder(String.format(
+                "Exception invoking method [%s] on object [%s], using arguments [", method.getName(), obj));
+        if (args != null)
+        {
+            for (int i = 0; i < args.length; i++)
+            {
+                message.append((i > 0 ? "," : "") + args[i]);
+            }
+        }
+        message.append("]");
+        return message.toString();
+    }
+
+    /**
+     * Set the accessibility flag on the {@link AccessibleObject} as described in
+     * {@link AccessibleObject#setAccessible(boolean)} within the context of a {@link PrivilegedAction}.
+     *
+     * @param <A>
+     *            member the accessible object type
+     * @param member
+     *            the accessible object
+     * @return the accessible object after the accessible flag has been altered
+     */
+    public static <A extends AccessibleObject> A setAccessible(final A member)
+    {
+        AccessController.doPrivileged(new PrivilegedAction<Void>()
+        {
+            @Override
+            public Void run()
+            {
+                member.setAccessible(true);
+                return null;
+            }
+        });
+        return member;
+    }
+
+    /**
+     * <p>
+     * Invoke the specified method on the provided instance, passing any additional arguments included in this method as
+     * arguments to the specified method.
+     * </p>
+     * <p/>
+     * <p>
+     * This method provides the same functionality and throws the same exceptions as
+     * {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the expected return type set to
+     * {@link Object} and no change to the method's accessibility.
+     * </p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static Object invokeMethod(Method method, Object instance, Object... args)
+    {
+        return invokeMethod(false, method, Object.class, instance, args);
+    }
+
+    /**
+     * <p>
+     * Invoke the specified method on the provided instance, passing any additional arguments included in this method as
+     * arguments to the specified method.
+     * </p>
+     * <p/>
+     * <p>
+     * This method attempts to set the accessible flag of the method in a {@link PrivilegedAction} before invoking the
+     * method if the first argument is true.
+     * </p>
+     * <p/>
+     * <p>
+     * This method provides the same functionality and throws the same exceptions as
+     * {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the expected return type set to
+     * {@link Object}.
+     * </p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static Object invokeMethod(boolean setAccessible, Method method, Object instance, Object... args)
+    {
+        return invokeMethod(setAccessible, method, Object.class, instance, args);
+    }
+
+    /**
+     * <p>
+     * Invoke the specified method on the provided instance, passing any additional arguments included in this method as
+     * arguments to the specified method.
+     * </p>
+     * <p/>
+     * <p>
+     * This method provides the same functionality and throws the same exceptions as
+     * {@link Reflections#invokeMethod(boolean, Method, Class, Object, Object...)}, with the expected return type set to
+     * {@link Object} and honoring the accessibility of the method.
+     * </p>
+     *
+     * @see Reflections#invokeMethod(boolean, Method, Class, Object, Object...)
+     * @see Method#invoke(Object, Object...)
+     */
+    public static <T> T invokeMethod(Method method, Class<T> expectedReturnType, Object instance, Object... args)
+    {
+        return invokeMethod(false, method, expectedReturnType, instance, args);
+    }
+
+    /**
+     * <p>
+     * Invoke the method on the instance, with any arguments specified, casting the result of invoking the method to the
+     * expected return type.
+     * </p>
+     * <p/>
+     * <p>
+     * This method wraps {@link Method#invoke(Object, Object...)}, converting the checked exceptions that
+     * {@link Method#invoke(Object, Object...)} specifies to runtime exceptions.
+     * </p>
+     * <p/>
+     * <p>
+     * If instructed, this method attempts to set the accessible flag of the method in a {@link PrivilegedAction} before
+     * invoking the method.
+     * </p>
+     *
+     * @param setAccessible
+     *            flag indicating whether method should first be set as accessible
+     * @param method
+     *            the method to invoke
+     * @param instance
+     *            the instance to invoke the method
+     * @param args
+     *            the arguments to the method
+     * @return the result of invoking the method, or null if the method's return type is void
+     * @throws RuntimeException
+     *             if this <code>Method</code> object enforces Java language access control and the underlying method is
+     *             inaccessible or if the underlying method throws an exception or if the initialization provoked by
+     *             this method fails.
+     * @throws IllegalArgumentException
+     *             if the method is an instance method and the specified <code>instance</code> argument is not an
+     *             instance of the class or interface declaring the underlying method (or of a subclass or implementor
+     *             thereof); if the number of actual and formal parameters differ; if an unwrapping conversion for
+     *             primitive arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to
+     *             the corresponding formal parameter type by a method invocation conversion.
+     * @throws NullPointerException
+     *             if the specified <code>instance</code> is null and the method is an instance method.
+     * @throws ClassCastException
+     *             if the result of invoking the method cannot be cast to the expectedReturnType
+     * @throws ExceptionInInitializerError
+     *             if the initialization provoked by this method fails.
+     * @see Method#invoke(Object, Object...)
+     */
+    public static <T> T invokeMethod(boolean setAccessible, Method method, Class<T> expectedReturnType,
+            Object instance, Object... args)
+    {
+        if (setAccessible && !method.isAccessible())
+        {
+            setAccessible(method);
+        }
+
+        try
+        {
+            return expectedReturnType.cast(method.invoke(instance, args));
+        }
+        catch (IllegalAccessException ex)
+        {
+            throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex);
+        }
+        catch (IllegalArgumentException ex)
+        {
+            throw new IllegalArgumentException(buildInvokeMethodErrorMessage(method, instance, args), ex);
+        }
+        catch (InvocationTargetException ex)
+        {
+            throw new RuntimeException(buildInvokeMethodErrorMessage(method, instance, args), ex.getCause());
+        }
+        catch (NullPointerException ex)
+        {
+            NullPointerException ex2 = new NullPointerException(buildInvokeMethodErrorMessage(method, instance, args));
+            ex2.initCause(ex.getCause());
+            throw ex2;
+        }
+        catch (ExceptionInInitializerError e)
+        {
+            ExceptionInInitializerError e2 = new ExceptionInInitializerError(buildInvokeMethodErrorMessage(method,
+                    instance, args));
+            e2.initCause(e.getCause());
+            throw e2;
+        }
+    }
+
+    /**
+     * <p>
+     * Set the value of a field on the instance to the specified value.
+     * </p>
+     * <p/>
+     * <p>
+     * This method provides the same functionality and throws the same exceptions as
+     * {@link Reflections#setFieldValue(boolean, Method, Class, Object, Object...)}, honoring the accessibility of the
+     * field.
+     * </p>
+     */
+    public static void setFieldValue(Field field, Object instance, Object value)
+    {
+        setFieldValue(false, field, instance, value);
+    }
+
+    /**
+     * <p>
+     * Sets the value of a field on the instance to the specified value.
+     * </p>
+     * <p/>
+     * <p>
+     * This method wraps {@link Field#set(Object, Object)}, converting the checked exceptions that
+     * {@link Field#set(Object, Object)} specifies to runtime exceptions.
+     * </p>
+     * <p/>
+     * <p>
+     * If instructed, this method attempts to set the accessible flag of the method in a {@link PrivilegedAction} before
+     * invoking the method.
+     * </p>
+     *
+     * @param field
+     *            the field on which to operate, or null if the field is static
+     * @param instance
+     *            the instance on which the field value should be set upon
+     * @param value
+     *            the value to set the field to
+     * @throws RuntimeException
+     *             if the underlying field is inaccessible.
+     * @throws IllegalArgumentException
+     *             if the specified <code>instance</code> is not an instance of the class or interface declaring the
+     *             underlying field (or a subclass or implementor thereof), or if an unwrapping conversion fails.
+     * @throws NullPointerException
+     *             if the specified <code>instance</code> is null and the field is an instance field.
+     * @throws ExceptionInInitializerError
+     *             if the initialization provoked by this method fails.
+     * @see Field#set(Object, Object)
+     */
+    public static void setFieldValue(boolean setAccessible, Field field, Object instance, Object value)
+    {
+        if (setAccessible && !field.isAccessible())
+        {
+            setAccessible(field);
+        }
+
+        try
+        {
+            field.set(instance, value);
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new RuntimeException(buildSetFieldValueErrorMessage(field, instance, value), e);
+        }
+        catch (NullPointerException ex)
+        {
+            NullPointerException ex2 = new NullPointerException(buildSetFieldValueErrorMessage(field, instance, value));
+            ex2.initCause(ex.getCause());
+            throw ex2;
+        }
+        catch (ExceptionInInitializerError e)
+        {
+            ExceptionInInitializerError e2 = new ExceptionInInitializerError(buildSetFieldValueErrorMessage(field,
+                    instance, value));
+            e2.initCause(e.getCause());
+            throw e2;
+        }
+    }
+
+    private static String buildSetFieldValueErrorMessage(Field field, Object obj, Object value)
+    {
+        return String.format("Exception setting [%s] field on object [%s] to value [%s]", field.getName(), obj, value);
+    }
+
+    private static String buildGetFieldValueErrorMessage(Field field, Object obj)
+    {
+        return String.format("Exception reading [%s] field from object [%s].", field.getName(), obj);
+    }
+
+    public static Object getFieldValue(Field field, Object instance)
+    {
+        return getFieldValue(field, instance, Object.class);
+    }
+
+    /**
+     * <p>
+     * Get the value of the field, on the specified instance, casting the value of the field to the expected type.
+     * </p>
+     * <p/>
+     * <p>
+     * This method wraps {@link Field#get(Object)}, converting the checked exceptions that {@link Field#get(Object)}
+     * specifies to runtime exceptions.
+     * </p>
+     *
+     * @param <T>
+     *            the type of the field's value
+     * @param field
+     *            the field to operate on
+     * @param instance
+     *            the instance from which to retrieve the value
+     * @param expectedType
+     *            the expected type of the field's value
+     * @return the value of the field
+     * @throws RuntimeException
+     *             if the underlying field is inaccessible.
+     * @throws IllegalArgumentException
+     *             if the specified <code>instance</code> is not an instance of the class or interface declaring the
+     *             underlying field (or a subclass or implementor thereof).
+     * @throws NullPointerException
+     *             if the specified <code>instance</code> is null and the field is an instance field.
+     * @throws ExceptionInInitializerError
+     *             if the initialization provoked by this method fails.
+     */
+    public static <T> T getFieldValue(Field field, Object instance, Class<T> expectedType)
+    {
+        try
+        {
+            return Reflections.cast(field.get(instance));
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new RuntimeException(buildGetFieldValueErrorMessage(field, instance), e);
+        }
+        catch (NullPointerException ex)
+        {
+            NullPointerException ex2 = new NullPointerException(buildGetFieldValueErrorMessage(field, instance));
+            ex2.initCause(ex.getCause());
+            throw ex2;
+        }
+        catch (ExceptionInInitializerError e)
+        {
+            ExceptionInInitializerError e2 = new ExceptionInInitializerError(buildGetFieldValueErrorMessage(field,
+                    instance));
+            e2.initCause(e.getCause());
+            throw e2;
+        }
+    }
+
+    /**
+     * Check if a class is serializable.
+     *
+     * @param clazz
+     *            The class to check
+     * @return true if the class implements serializable or is a primitive
+     */
+    public static boolean isSerializable(Class<?> clazz)
+    {
+        return clazz.isPrimitive() || Serializable.class.isAssignableFrom(clazz);
+    }
+
+    /**
+     * Gets the property name from a getter method.
+     * <p/>
+     * We extend JavaBean conventions, allowing the getter method to have parameters
+     *
+     * @param method
+     *            The getter method
+     * @return The name of the property. Returns null if method wasn't JavaBean getter-styled
+     */
+    public static String getPropertyName(Method method)
+    {
+        String methodName = method.getName();
+        if (methodName.matches("^(get).*"))
+        {
+            return Introspector.decapitalize(methodName.substring(3));
+        }
+        else if (methodName.matches("^(is).*"))
+        {
+            return Introspector.decapitalize(methodName.substring(2));
+        }
+        else
+        {
+            return null;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/AnnotatedPropertyCriteria.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/AnnotatedPropertyCriteria.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/AnnotatedPropertyCriteria.java
new file mode 100644
index 0000000..7fd91d2
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/AnnotatedPropertyCriteria.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on its annotations
+ *
+ * @author Shane Bryzak
+ * @see PropertyCriteria
+ */
+public class AnnotatedPropertyCriteria implements PropertyCriteria
+{
+    private final Class<? extends Annotation> annotationClass;
+
+    public AnnotatedPropertyCriteria(Class<? extends Annotation> annotationClass)
+    {
+        this.annotationClass = annotationClass;
+    }
+
+    @Override
+    public boolean fieldMatches(Field f)
+    {
+        return f.isAnnotationPresent(annotationClass);
+    }
+
+    @Override
+    public boolean methodMatches(Method m)
+    {
+        return m.isAnnotationPresent(annotationClass);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/NamedPropertyCriteria.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/NamedPropertyCriteria.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/NamedPropertyCriteria.java
new file mode 100644
index 0000000..c976c7e
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/NamedPropertyCriteria.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on name
+ *
+ * @author Shane Bryzak
+ * @see PropertyCriteria
+ */
+public class NamedPropertyCriteria implements PropertyCriteria
+{
+    private final String[] propertyNames;
+
+    public NamedPropertyCriteria(String... propertyNames)
+    {
+        this.propertyNames = propertyNames;
+    }
+
+    @Override
+    public boolean fieldMatches(Field f)
+    {
+        for (String propertyName : propertyNames)
+        {
+            if (propertyName.equals(f.getName()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean methodMatches(Method m)
+    {
+        for (String propertyName : propertyNames)
+        {
+            if (m.getName().startsWith("get") &&
+                    Introspector.decapitalize(m.getName().substring(3)).equals(propertyName))
+            {
+                return true;
+            }
+
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyCriteria.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyCriteria.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyCriteria.java
new file mode 100644
index 0000000..50e09d9
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyCriteria.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * <p>
+ * A property criteria can be used to filter the properties found by a {@link PropertyQuery}
+ * </p>
+ * <p/>
+ * <p>
+ * Solder provides a number of property queries ( {@link TypedPropertyCriteria}, {@link NamedPropertyCriteria} and
+ * {@link AnnotatedPropertyCriteria}), or you can create a custom query by implementing this interface.
+ * </p>
+ *
+ * @author Shane Bryzak
+ * @see PropertyQuery#addCriteria(PropertyCriteria)
+ * @see PropertyQueries
+ * @see TypedPropertyCriteria
+ * @see AnnotatedPropertyCriteria
+ * @see NamedPropertyCriteria
+ */
+public interface PropertyCriteria
+{
+    /**
+     * Tests whether the specified field matches the criteria
+     *
+     * @param f
+     * @return true if the field matches
+     */
+    boolean fieldMatches(Field f);
+
+    /**
+     * Tests whether the specified method matches the criteria
+     *
+     * @param m
+     * @return true if the method matches
+     */
+    boolean methodMatches(Method m);
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQueries.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQueries.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQueries.java
new file mode 100644
index 0000000..a79b0be
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQueries.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+/**
+ * Utilities for working with property queries
+ *
+ * @author Shane Bryzak
+ * @author Pete Muir
+ * @see PropertyQuery
+ */
+public class PropertyQueries
+{
+
+    private PropertyQueries()
+    {
+    }
+
+    /**
+     * Create a new {@link PropertyQuery}
+     *
+     * @param <V>
+     * @param targetClass
+     * @return
+     */
+    public static <V> PropertyQuery<V> createQuery(Class<?> targetClass)
+    {
+        return new PropertyQuery<V>(targetClass);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQuery.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQuery.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQuery.java
new file mode 100644
index 0000000..9d889e9
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/PropertyQuery.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.deltaspike.data.impl.property.MethodProperty;
+import org.apache.deltaspike.data.impl.property.Properties;
+import org.apache.deltaspike.data.impl.property.Property;
+
+/**
+ * <p>
+ * Queries a target class for properties that match certain criteria. A property may either be a private or public
+ * field, declared by the target class or inherited from a superclass, or a public method declared by the target class
+ * or inherited from any of its superclasses. For properties that are exposed via a method, the property must be a
+ * JavaBean style property, i.e. it must provide both an accessor and mutator method according to the JavaBean
+ * specification.
+ * </p>
+ * <p/>
+ * <p>
+ * This class is not thread-safe, however the result returned by the getResultList() method is.
+ * </p>
+ *
+ * @author Shane Bryzak
+ * @see PropertyQueries
+ * @see PropertyCriteria
+ */
+public class PropertyQuery<V>
+{
+    private final Class<?> targetClass;
+    private final List<PropertyCriteria> criteria;
+
+    PropertyQuery(Class<?> targetClass)
+    {
+        if (targetClass == null)
+        {
+            throw new IllegalArgumentException("targetClass parameter may not be null");
+        }
+
+        this.targetClass = targetClass;
+        this.criteria = new ArrayList<PropertyCriteria>();
+    }
+
+    /**
+     * Add a criteria to query
+     *
+     * @param criteria
+     *            the criteria to add
+     */
+    public PropertyQuery<V> addCriteria(PropertyCriteria criteria)
+    {
+        this.criteria.add(criteria);
+        return this;
+    }
+
+    /**
+     * Get the first result from the query, causing the query to be run.
+     *
+     * @return the first result, or null if there are no results
+     */
+    public Property<V> getFirstResult()
+    {
+        List<Property<V>> results = getResultList();
+        return results.isEmpty() ? null : results.get(0);
+    }
+
+    /**
+     * Get the first result from the query that is not marked as read only, causing the query to be run.
+     *
+     * @return the first writable result, or null if there are no results
+     */
+    public Property<V> getFirstWritableResult()
+    {
+        List<Property<V>> results = getWritableResultList();
+        return results.isEmpty() ? null : results.get(0);
+    }
+
+    /**
+     * Get a single result from the query, causing the query to be run. An exception is thrown if the query does not
+     * return exactly one result.
+     *
+     * @return the single result
+     * @throws RuntimeException
+     *             if the query does not return exactly one result
+     */
+    public Property<V> getSingleResult()
+    {
+        List<Property<V>> results = getResultList();
+        if (results.size() == 1)
+        {
+            return results.get(0);
+        }
+        else if (results.isEmpty())
+        {
+            throw new RuntimeException("Expected one property match, but the criteria did not match any properties on "
+                    + targetClass.getName());
+        }
+        else
+        {
+            throw new RuntimeException("Expected one property match, but the criteria matched " + results.size()
+                    + " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get a single result from the query that is not marked as read only, causing the query to be run. An exception is
+     * thrown if the query does not return exactly one result.
+     *
+     * @return the single writable result
+     * @throws RuntimeException
+     *             if the query does not return exactly one result
+     */
+    public Property<V> getWritableSingleResult()
+    {
+        List<Property<V>> results = getWritableResultList();
+        if (results.size() == 1)
+        {
+            return results.get(0);
+        }
+        else if (results.isEmpty())
+        {
+            throw new RuntimeException("Expected one property match, but the criteria did not match any properties on "
+                    + targetClass.getName());
+        }
+        else
+        {
+            throw new RuntimeException("Expected one property match, but the criteria matched " + results.size()
+                    + " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public List<Property<V>> getResultList()
+    {
+        return getResultList(false);
+    }
+
+    /**
+     * Get the non read only results from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public List<Property<V>> getWritableResultList()
+    {
+        return getResultList(true);
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @param writable
+     *            if this query should only return properties that are not read only
+     * @return the results, or an empty list if there are no results
+     */
+    private List<Property<V>> getResultList(boolean writable)
+    {
+        List<Property<V>> results = new ArrayList<Property<V>>();
+
+        // First check public accessor methods (we ignore private methods)
+        for (Method method : targetClass.getMethods())
+        {
+            if (!(method.getName().startsWith("is") || method.getName().startsWith("get")))
+            {
+                continue;
+            }
+
+            boolean match = true;
+            for (PropertyCriteria c : criteria)
+            {
+                if (!c.methodMatches(method))
+                {
+                    match = false;
+                    break;
+                }
+            }
+            if (match)
+            {
+                MethodProperty<V> property = Properties.<V> createProperty(method);
+                if (!writable || !property.isReadOnly())
+                {
+                    results.add(property);
+                }
+            }
+        }
+
+        Class<?> cls = targetClass;
+        while (cls != null && !cls.equals(Object.class))
+        {
+            // Now check declared fields
+            for (Field field : cls.getDeclaredFields())
+            {
+                boolean match = true;
+                for (PropertyCriteria c : criteria)
+                {
+                    if (!c.fieldMatches(field))
+                    {
+                        match = false;
+                        break;
+                    }
+                }
+                Property<V> prop = Properties.<V> createProperty(field);
+
+                if (match && !resultsContainsProperty(results, prop.getName()))
+                {
+                    if (!writable || !prop.isReadOnly())
+                    {
+                        results.add(prop);
+                    }
+                }
+            }
+
+            cls = cls.getSuperclass();
+        }
+
+        return results;
+    }
+
+    private boolean resultsContainsProperty(List<Property<V>> results, String propertyName)
+    {
+        for (Property<V> p : results)
+        {
+            if (propertyName.equals(p.getName()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/TypedPropertyCriteria.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/TypedPropertyCriteria.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/TypedPropertyCriteria.java
new file mode 100644
index 0000000..19b71f2
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/query/TypedPropertyCriteria.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.property.query;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on its type
+ *
+ * @author Shane Bryzak
+ * @see PropertyCriteria
+ */
+public class TypedPropertyCriteria implements PropertyCriteria
+{
+    private final Class<?> propertyClass;
+
+    public TypedPropertyCriteria(Class<?> propertyClass)
+    {
+        this.propertyClass = propertyClass;
+    }
+
+    @Override
+    public boolean fieldMatches(Field f)
+    {
+        return propertyClass.equals(f.getType());
+    }
+
+    @Override
+    public boolean methodMatches(Method m)
+    {
+        return propertyClass.equals(m.getReturnType());
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/EntityUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/EntityUtils.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/EntityUtils.java
new file mode 100755
index 0000000..5f5c966
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/EntityUtils.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+
+import org.apache.deltaspike.data.impl.meta.unit.PersistenceUnits;
+import org.apache.deltaspike.data.impl.meta.verifier.EntityVerifier;
+import org.apache.deltaspike.data.impl.property.Property;
+import org.apache.deltaspike.data.impl.property.query.AnnotatedPropertyCriteria;
+import org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria;
+import org.apache.deltaspike.data.impl.property.query.PropertyCriteria;
+import org.apache.deltaspike.data.impl.property.query.PropertyQueries;
+import org.apache.deltaspike.data.impl.property.query.PropertyQuery;
+
+public final class EntityUtils
+{
+
+    private EntityUtils()
+    {
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static Class<? extends Serializable> primaryKeyClass(Class<?> entityClass)
+    {
+        if (entityClass.isAnnotationPresent(IdClass.class))
+        {
+            return entityClass.getAnnotation(IdClass.class).value(); // Serializablity isn't required, could cause
+                                                                     // problems
+        }
+        Class clazz = PersistenceUnits.instance().primaryKeyIdClass(entityClass);
+        if (clazz != null)
+        {
+            return clazz;
+        }
+        Property<Serializable> property = primaryKey(entityClass);
+        return property.getJavaClass();
+    }
+
+    public static Object primaryKeyValue(Object entity)
+    {
+        Property<Serializable> property = primaryKey(entity.getClass());
+        return property.getValue(entity);
+    }
+
+    public static String entityName(Class<?> entityClass)
+    {
+        String result = null;
+        if (entityClass.isAnnotationPresent(Entity.class))
+        {
+            result = entityClass.getAnnotation(Entity.class).name();
+        }
+        else
+        {
+            result = PersistenceUnits.instance().entityName(entityClass);
+        }
+        return (result != null && !"".equals(result)) ? result : entityClass.getSimpleName();
+    }
+
+    public static boolean isEntityClass(Class<?> entityClass)
+    {
+        return new EntityVerifier().verify(entityClass);
+    }
+
+    private static Property<Serializable> primaryKey(Class<?> entityClass)
+    {
+        for (PropertyCriteria c : criteriaList(entityClass))
+        {
+            PropertyQuery<Serializable> query = PropertyQueries.<Serializable> createQuery(entityClass)
+                    .addCriteria(c);
+            if (query.getFirstResult() != null)
+            {
+                return query.getFirstResult();
+            }
+        }
+        throw new IllegalStateException("Class " + entityClass + " has no id defined");
+    }
+
+    private static List<PropertyCriteria> criteriaList(Class<?> entityClass)
+    {
+        List<PropertyCriteria> criteria = new LinkedList<PropertyCriteria>();
+        criteria.add(new AnnotatedPropertyCriteria(Id.class));
+        criteria.add(new AnnotatedPropertyCriteria(EmbeddedId.class));
+        String fromMappingFiles = PersistenceUnits.instance().primaryKeyField(entityClass);
+        if (fromMappingFiles != null)
+        {
+            criteria.add(new NamedPropertyCriteria(fromMappingFiles));
+        }
+        return criteria;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/QueryUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/QueryUtils.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/QueryUtils.java
new file mode 100644
index 0000000..d844bc4
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/QueryUtils.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util;
+
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.Collection;
+
+/**
+ *
+ * @author thomashug
+ */
+public final class QueryUtils
+{
+    private static final String KEYWORD_SPLITTER = "({0})(?=[A-Z])";
+
+    private QueryUtils()
+    {
+    }
+
+    public static String[] splitByKeyword(String query, String keyword)
+    {
+        return query.split(MessageFormat.format(KEYWORD_SPLITTER, keyword));
+    }
+
+    public static String uncapitalize(String value)
+    {
+        if (isEmpty(value))
+        {
+            return null;
+        }
+        if (value.length() == 1)
+        {
+            return value.toLowerCase();
+        }
+        return value.substring(0, 1).toLowerCase() + value.substring(1);
+    }
+
+    public static boolean isEmpty(String text)
+    {
+        return text == null || "".equals(text);
+    }
+
+    public static boolean isNotEmpty(String text)
+    {
+        return !isEmpty(text);
+    }
+
+    public static boolean isEmpty(Collection<?> collection)
+    {
+        return collection == null || collection.isEmpty();
+    }
+
+    public static boolean isEmpty(Object[] array)
+    {
+        return array == null || array.length == 0;
+    }
+
+    public static boolean isString(Object value)
+    {
+        return value != null && value instanceof String;
+    }
+
+    public static boolean contains(Class<?> clazz, Method method)
+    {
+        return extract(clazz, method) != null;
+    }
+
+    public static Method extract(Class<?> clazz, Method method)
+    {
+        try
+        {
+            String name = method.getName();
+            return clazz.getMethod(name, method.getParameterTypes());
+        }
+        catch (NoSuchMethodException e)
+        {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/BaseQueryStringExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/BaseQueryStringExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/BaseQueryStringExtractor.java
new file mode 100644
index 0000000..f1c7074
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/BaseQueryStringExtractor.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import java.lang.reflect.Method;
+
+public abstract class BaseQueryStringExtractor implements QueryStringExtractor
+{
+
+    Object invoke(String methodName, Object target)
+    {
+        try
+        {
+            Method method = target.getClass().getMethod(methodName);
+            return method.invoke(target);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/EclipseLinkEjbQueryStringExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/EclipseLinkEjbQueryStringExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/EclipseLinkEjbQueryStringExtractor.java
new file mode 100644
index 0000000..31cfd43
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/EclipseLinkEjbQueryStringExtractor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import javax.persistence.Query;
+
+@ProviderSpecific("org.eclipse.persistence.jpa.JpaQuery")
+public class EclipseLinkEjbQueryStringExtractor extends BaseQueryStringExtractor
+{
+
+    @Override
+    public String extractFrom(Query query)
+    {
+        Object dbQuery = invoke("getDatabaseQuery", query);
+        return (String) invoke("getJPQLString", dbQuery);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/HibernateQueryStringExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/HibernateQueryStringExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/HibernateQueryStringExtractor.java
new file mode 100644
index 0000000..ba8b7a5
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/HibernateQueryStringExtractor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import javax.persistence.Query;
+
+@ProviderSpecific("org.hibernate.ejb.HibernateQuery")
+public class HibernateQueryStringExtractor extends BaseQueryStringExtractor
+{
+
+    @Override
+    public String extractFrom(Query query)
+    {
+        Object hibernateQuery = invoke("getHibernateQuery", query);
+        return (String) invoke("getQueryString", hibernateQuery);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/OpenJpaQueryStringExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/OpenJpaQueryStringExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/OpenJpaQueryStringExtractor.java
new file mode 100644
index 0000000..1abcb9e
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/OpenJpaQueryStringExtractor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import javax.persistence.Query;
+
+@ProviderSpecific("org.apache.openjpa.persistence.OpenJPAQuery")
+public class OpenJpaQueryStringExtractor extends BaseQueryStringExtractor
+{
+
+    @Override
+    public String extractFrom(Query query)
+    {
+        return (String) invoke("getQueryString", query);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/ProviderSpecific.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/ProviderSpecific.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/ProviderSpecific.java
new file mode 100644
index 0000000..b07a22c
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/ProviderSpecific.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({ TYPE })
+@Retention(RUNTIME)
+public @interface ProviderSpecific
+{
+
+    String value();
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractor.java
new file mode 100644
index 0000000..48d9f68
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractor.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import javax.persistence.Query;
+
+public interface QueryStringExtractor
+{
+
+    String extractFrom(Query query);
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractorFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractorFactory.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractorFactory.java
new file mode 100644
index 0000000..b005292
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/util/jpa/QueryStringExtractorFactory.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl.util.jpa;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.persistence.Query;
+
+public class QueryStringExtractorFactory
+{
+
+    private final List<QueryStringExtractor> extractors = Arrays.<QueryStringExtractor> asList(
+            new HibernateQueryStringExtractor(),
+            new EclipseLinkEjbQueryStringExtractor(),
+            new OpenJpaQueryStringExtractor());
+
+    public QueryStringExtractor select(Query query)
+    {
+        for (QueryStringExtractor extractor : extractors)
+        {
+            String compare = extractor.getClass().getAnnotation(ProviderSpecific.class).value();
+            if (isQueryClass(compare, query))
+            {
+                return extractor;
+            }
+        }
+        throw new RuntimeException("Persistence provider not supported");
+    }
+
+    private boolean isQueryClass(String clazzName, Query query)
+    {
+        try
+        {
+            Class<?> toClass = Class.forName(clazzName);
+            toClass.cast(query);
+            return true;
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/resources/META-INF/beans.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/resources/META-INF/beans.xml b/deltaspike/modules/data/impl/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..7551e97
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+-->
+<beans  xmlns="http://java.sun.com/xml/ns/javaee" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns:weld="http://jboss.org/schema/weld/beans" 
+        xsi:schemaLocation="
+            http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd
+            http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd">
+</beans>

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/deltaspike/modules/data/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100755
index 0000000..a1235b3
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1,20 @@
+#####################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#####################################################################################
+
+org.apache.deltaspike.data.impl.RepositoryExtension
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java
new file mode 100644
index 0000000..98efe19
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/QueryResultTest.java
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.persistence.EntityManager;
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.PersistenceContext;
+
+import org.apache.deltaspike.data.api.QueryResult;
+import org.apache.deltaspike.data.test.TransactionalTestCase;
+import org.apache.deltaspike.data.test.domain.Simple;
+import org.apache.deltaspike.data.test.domain.SimpleBuilder;
+import org.apache.deltaspike.data.test.domain.Simple_;
+import org.apache.deltaspike.data.test.service.SimpleRepository;
+import org.apache.deltaspike.data.test.util.TestDeployments;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.shrinkwrap.api.Archive;
+import org.junit.Before;
+import org.junit.Test;
+
+public class QueryResultTest extends TransactionalTestCase
+{
+
+    @Deployment
+    public static Archive<?> deployment()
+    {
+        return TestDeployments.initDeployment()
+                .addClasses(SimpleRepository.class)
+                .addPackage(Simple.class.getPackage());
+    }
+
+    @Inject
+    private SimpleRepository repo;
+
+    @Produces
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    private SimpleBuilder builder;
+
+    @Test
+    public void should_sort_result()
+    {
+        // given
+        final String name = "testSortResult";
+        builder.createSimple(name, Integer.valueOf(99));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(56));
+        builder.createSimple(name, Integer.valueOf(123));
+
+        // when
+        List<Simple> result = repo.findByName(name)
+                .orderDesc(Simple_.counter)
+                .orderAsc(Simple_.id)
+                .getResultList();
+
+        // then
+        assertNotNull(result);
+        assertFalse(result.isEmpty());
+        int lastCounter = Integer.MAX_VALUE;
+        long lastId = Long.MIN_VALUE;
+        for (Simple simple : result)
+        {
+            int currentCounter = simple.getCounter().intValue();
+            long currentId = simple.getId().longValue();
+            if (currentCounter == lastCounter)
+            {
+                assertTrue(currentId > lastId);
+            }
+            else
+            {
+                assertTrue(currentCounter < lastCounter);
+            }
+            lastCounter = currentCounter;
+            lastId = currentId;
+        }
+    }
+
+    @Test
+    public void should_change_sort_order()
+    {
+        // given
+        final String name = "testChangeSortOrder";
+        builder.createSimple(name, Integer.valueOf(99));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(229));
+
+        // when
+        QueryResult<Simple> query = repo.findByName(name);
+        List<Simple> result1 = query
+                .changeOrder(Simple_.counter)
+                .getResultList();
+        List<Simple> result2 = query
+                .changeOrder(Simple_.counter)
+                .getResultList();
+
+        // then
+        assertEquals(22, result1.get(0).getCounter().intValue());
+        assertEquals(229, result2.get(0).getCounter().intValue());
+    }
+
+    @Test
+    public void should_clear_sort_order()
+    {
+        // given
+        final String name = "testClearSortOrder";
+        builder.createSimple(name, Integer.valueOf(99));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(229));
+
+        // when
+        QueryResult<Simple> query = repo.findByName(name);
+        List<Simple> result1 = query
+                .changeOrder(Simple_.counter)
+                .getResultList();
+        List<Simple> result2 = query
+                .clearOrder()
+                .getResultList();
+
+        // then
+        assertEquals(result1.size(), result2.size());
+        for (int i = 0; i < result1.size(); i++)
+        {
+            int count1 = result1.get(i).getCounter().intValue();
+            int count2 = result2.get(i).getCounter().intValue();
+            if (count1 != count2)
+            {
+                return;
+            }
+        }
+        fail("Both collections sorted: " + result1 + "," + result2);
+    }
+
+    @Test
+    public void should_page_result()
+    {
+        // given
+        final String name = "testPageResult";
+        builder.createSimple(name, Integer.valueOf(99));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(56));
+        builder.createSimple(name, Integer.valueOf(123));
+
+        // when
+        List<Simple> result = repo.findByName(name)
+                .hint("javax.persistence.query.timeout", 10000)
+                .lockMode(LockModeType.NONE)
+                .flushMode(FlushModeType.COMMIT)
+                .orderDesc(Simple_.counter)
+                .firstResult(2)
+                .maxResults(2)
+                .getResultList();
+
+        // then
+        assertNotNull(result);
+        assertFalse(result.isEmpty());
+        assertEquals(2, result.size());
+    }
+
+    @Test
+    public void should_page_with_page_api()
+    {
+        // given
+        final String name = "testPageAPI";
+        builder.createSimple(name, Integer.valueOf(22));
+        builder.createSimple(name, Integer.valueOf(56));
+        builder.createSimple(name, Integer.valueOf(99));
+        builder.createSimple(name, Integer.valueOf(123));
+        builder.createSimple(name, Integer.valueOf(229));
+        builder.createSimple(name, Integer.valueOf(299));
+        builder.createSimple(name, Integer.valueOf(389));
+
+        // when
+        QueryResult<Simple> pagedQuery = repo
+                .findByName(name)
+                .withPageSize(2);
+        List<Simple> result1 = pagedQuery.getResultList();
+        List<Simple> result2 = pagedQuery.nextPage().nextPage().getResultList();
+        int current = pagedQuery.currentPage();
+        List<Simple> result3 = pagedQuery.toPage(1).getResultList();
+        int total = pagedQuery.countPages();
+        int pageSize = pagedQuery.pageSize();
+
+        // then
+        assertEquals(2, result1.size());
+        assertEquals(2, result2.size());
+        assertEquals(2, result3.size());
+        assertEquals(2, current);
+        assertEquals(4, total);
+        assertEquals(2, pageSize);
+
+        assertEquals(22, result1.get(0).getCounter().intValue());
+        assertEquals(229, result2.get(0).getCounter().intValue());
+        assertEquals(99, result3.get(0).getCounter().intValue());
+
+    }
+
+    @Test
+    public void should_modify_named_query()
+    {
+        // given
+        final String name = "testModifyNamedQuery";
+        builder.createSimple(name + 0);
+        builder.createSimple(name + 1);
+        builder.createSimple(name + 2);
+        builder.createSimple(name + 3);
+
+        // when
+        List<Simple> result = repo.queryResultWithNamed(name + "%")
+                .orderDesc(Simple_.name)
+                .getResultList();
+
+        // then
+        assertEquals(4, result.size());
+        assertEquals(name + 3, result.get(0).getName());
+        assertEquals(name + 2, result.get(1).getName());
+    }
+
+    @Test
+    public void should_count_with_method_query()
+    {
+        // given
+        final String name = "testCountWithMethodQuery";
+        builder.createSimple(name);
+        builder.createSimple(name);
+
+        // when
+        long result = repo.findByName(name).count();
+
+        // then
+        assertEquals(2L, result);
+    }
+
+    @Test
+    public void should_count_with_named_query()
+    {
+        // given
+        final String name = "testCountWithNamedQuery";
+        builder.createSimple(name);
+        builder.createSimple(name);
+
+        // when
+        long result = repo.queryResultWithNamed(name).count();
+
+        // then
+        assertEquals(2L, result);
+    }
+
+    @Before
+    public void setup()
+    {
+        builder = new SimpleBuilder(entityManager);
+    }
+
+    @Override
+    protected EntityManager getEntityManager()
+    {
+        return entityManager;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/RepositoryExtensionTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/RepositoryExtensionTest.java b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/RepositoryExtensionTest.java
new file mode 100755
index 0000000..8a2fa18
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/test/java/org/apache/deltaspike/data/impl/RepositoryExtensionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.data.impl;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+import org.apache.deltaspike.data.test.domain.Simple;
+import org.apache.deltaspike.data.test.service.ExtendedRepositoryInterface;
+import org.apache.deltaspike.data.test.service.RepositoryInterface;
+import org.apache.deltaspike.data.test.service.SimpleRepository;
+import org.apache.deltaspike.data.test.util.TestDeployments;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(Arquillian.class)
+public class RepositoryExtensionTest
+{
+
+    @Deployment
+    public static Archive<?> deployment()
+    {
+        return TestDeployments.initDeployment()
+                .addClasses(RepositoryInterface.class,
+                            ExtendedRepositoryInterface.class,
+                            SimpleRepository.class)
+                .addPackages(true, Simple.class.getPackage());
+    }
+
+    @Inject
+    Instance<RepositoryInterface> repo;
+
+    @Inject
+    Instance<ExtendedRepositoryInterface> extendedRepo;
+
+    @Inject
+    Instance<SimpleRepository> extendedClassRepo;
+
+    @Test
+    public void should_inject()
+    {
+        assertNotNull(repo.get());
+        assertNotNull(extendedRepo.get());
+        assertNotNull(extendedClassRepo.get());
+    }
+
+}


Mime
View raw message