From 1a3e0806c4dd23e9804cfd79611666834aa80fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Thu, 19 Apr 2012 22:53:23 +0300 Subject: [PATCH] removed empty package --- .../query/collections/EvaluatorFunction.java | 40 + .../main/java/com/mysema/util/BeanMap.java | 880 ++++++++++++++++++ .../main/java/com/mysema/util/FileUtils.java | 19 + 3 files changed, 939 insertions(+) create mode 100644 querydsl-collections/src/main/java/com/mysema/query/collections/EvaluatorFunction.java create mode 100644 querydsl-core/src/main/java/com/mysema/util/BeanMap.java create mode 100644 querydsl-core/src/main/java/com/mysema/util/FileUtils.java diff --git a/querydsl-collections/src/main/java/com/mysema/query/collections/EvaluatorFunction.java b/querydsl-collections/src/main/java/com/mysema/query/collections/EvaluatorFunction.java new file mode 100644 index 000000000..6eb7b3cbd --- /dev/null +++ b/querydsl-collections/src/main/java/com/mysema/query/collections/EvaluatorFunction.java @@ -0,0 +1,40 @@ +/* + * Copyright 2011, Mysema Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mysema.query.collections; + +import com.google.common.base.Function; +import com.mysema.codegen.Evaluator; + +/** + * Function implementation which uses an Evaluator for transformation + * + * @author tiwe + */ +public class EvaluatorFunction implements Function { + + private final Evaluator ev; + + public EvaluatorFunction(Evaluator ev) { + this.ev = ev; + } + + @Override + public T apply(S input) { + if (input.getClass().isArray()) { + return ev.evaluate((Object[]) input); + } else { + return ev.evaluate(new Object[]{input}); + } + } +} diff --git a/querydsl-core/src/main/java/com/mysema/util/BeanMap.java b/querydsl-core/src/main/java/com/mysema/util/BeanMap.java new file mode 100644 index 000000000..9aae8b2ff --- /dev/null +++ b/querydsl-core/src/main/java/com/mysema/util/BeanMap.java @@ -0,0 +1,880 @@ +/* + * 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 com.mysema.util; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.google.common.base.Function; + + +/** + * An implementation of Map for JavaBeans which uses introspection to + * get and put properties in the bean. + *

+ * If an exception occurs during attempts to get or set a property then the + * property is considered non existent in the Map + * + * @version $Revision: 812176 $ $Date: 2009-09-07 15:59:25 +0100 (Mon, 07 Sep 2009) $ + * + * @author James Strachan + * @author Stephen Colebourne + */ +public class BeanMap extends AbstractMap implements Cloneable { + + private transient Object bean; + + private transient HashMap readMethods = new HashMap(); + private transient HashMap writeMethods = new HashMap(); + private transient HashMap types = new HashMap(); + + /** + * An empty array. Used to invoke accessors via reflection. + */ + public static final Object[] NULL_ARGUMENTS = {}; + + /** + * Maps primitive Class types to applyers. The applyer + * apply strings into the appropriate primitive wrapper. + * + * N.B. private & unmodifiable replacement for the (public & static) defaultFunctions instance. + */ + private static final Map typeFunctions = Collections.unmodifiableMap(createTypeFunctions()); + + /** + * This HashMap has been made unmodifiable to prevent issues when + * loaded in a shared ClassLoader enviroment. + * + * @see "http://issues.apache.org/jira/browse/BEANUTILS-112" + * @deprecated Use {@link BeanMap#getTypeFunction(Class)} method + */ + public static HashMap defaultFunctions = new HashMap() { + public void clear() { + throw new UnsupportedOperationException(); + } + public boolean containsKey(Object key) { + return typeFunctions.containsKey(key); + } + public boolean containsValue(Object value) { + return typeFunctions.containsValue(value); + } + public Set entrySet() { + return typeFunctions.entrySet(); + } + public Object get(Object key) { + return typeFunctions.get(key); + } + public boolean isEmpty() { + return false; + } + public Set keySet() { + return typeFunctions.keySet(); + } + public Object put(Object key, Object value) { + throw new UnsupportedOperationException(); + } + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + public Object remove(Object key) { + throw new UnsupportedOperationException(); + } + public int size() { + return typeFunctions.size(); + } + public Collection values() { + return typeFunctions.values(); + } + }; + + private static Map createTypeFunctions() { + Map defaultFunctions = new HashMap(); + defaultFunctions.put( + Boolean.TYPE, + new Function() { + public Object apply( Object input ) { + return Boolean.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Character.TYPE, + new Function() { + public Object apply( Object input ) { + return new Character( input.toString().charAt( 0 ) ); + } + } + ); + defaultFunctions.put( + Byte.TYPE, + new Function() { + public Object apply( Object input ) { + return Byte.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Short.TYPE, + new Function() { + public Object apply( Object input ) { + return Short.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Integer.TYPE, + new Function() { + public Object apply( Object input ) { + return Integer.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Long.TYPE, + new Function() { + public Object apply( Object input ) { + return Long.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Float.TYPE, + new Function() { + public Object apply( Object input ) { + return Float.valueOf( input.toString() ); + } + } + ); + defaultFunctions.put( + Double.TYPE, + new Function() { + public Object apply( Object input ) { + return Double.valueOf( input.toString() ); + } + } + ); + return defaultFunctions; + } + + + // Constructors + //------------------------------------------------------------------------- + + /** + * Constructs a new empty BeanMap. + */ + public BeanMap() { + } + + /** + * Constructs a new BeanMap that operates on the + * specified bean. If the given bean is null, then + * this map will be empty. + * + * @param bean the bean for this map to operate on + */ + public BeanMap(Object bean) { + this.bean = bean; + initialise(); + } + + // Map interface + //------------------------------------------------------------------------- + + /** + * Renders a string representation of this object. + * @return a String representation of this object + */ + public String toString() { + return "BeanMap<" + String.valueOf(bean) + ">"; + } + + /** + * Clone this bean map using the following process: + * + *

    + *
  • If there is no underlying bean, return a cloned BeanMap without a + * bean. + * + *
  • Since there is an underlying bean, try to instantiate a new bean of + * the same type using Class.newInstance(). + * + *
  • If the instantiation fails, throw a CloneNotSupportedException + * + *
  • Clone the bean map and set the newly instantiated bean as the + * underlying bean for the bean map. + * + *
  • Copy each property that is both readable and writable from the + * existing object to a cloned bean map. + * + *
  • If anything fails along the way, throw a + * CloneNotSupportedException. + * + *
      + * + * @return a cloned instance of this bean map + * @throws CloneNotSupportedException if the underlying bean + * cannot be cloned + */ + public Object clone() throws CloneNotSupportedException { + BeanMap newMap = (BeanMap)super.clone(); + + if(bean == null) { + // no bean, just an empty bean map at the moment. return a newly + // cloned and empty bean map. + return newMap; + } + + Object newBean = null; + Class beanClass = bean.getClass(); // Cannot throw Exception + try { + newBean = beanClass.newInstance(); + } catch (Exception e) { + // unable to instantiate + throw new CloneNotSupportedException + ("Unable to instantiate the underlying bean \"" + + beanClass.getName() + "\": " + e); + } + + try { + newMap.setBean(newBean); + } catch (Exception exception) { + throw new CloneNotSupportedException + ("Unable to set bean in the cloned bean map: " + + exception); + } + + try { + // copy only properties that are readable and writable. If its + // not readable, we can't get the value from the old map. If + // its not writable, we can't write a value into the new map. + Iterator readableKeys = readMethods.keySet().iterator(); + while(readableKeys.hasNext()) { + String key = readableKeys.next(); + if(getWriteMethod(key) != null) { + newMap.put(key, get(key)); + } + } + } catch (Exception exception) { + throw new CloneNotSupportedException + ("Unable to copy bean values to cloned bean map: " + + exception); + } + + return newMap; + } + + /** + * Puts all of the writable properties from the given BeanMap into this + * BeanMap. Read-only and Write-only properties will be ignored. + * + * @param map the BeanMap whose properties to put + */ + public void putAllWriteable(BeanMap map) { + Iterator readableKeys = map.readMethods.keySet().iterator(); + while (readableKeys.hasNext()) { + String key = readableKeys.next(); + if (getWriteMethod(key) != null) { + this.put(key, map.get(key)); + } + } + } + + + /** + * This method reinitializes the bean map to have default values for the + * bean's properties. This is accomplished by constructing a new instance + * of the bean which the map uses as its underlying data source. This + * behavior for clear() differs from the Map contract in that + * the mappings are not actually removed from the map (the mappings for a + * BeanMap are fixed). + */ + public void clear() { + if(bean == null) { + return; + } + + Class beanClass = null; + try { + beanClass = bean.getClass(); + bean = beanClass.newInstance(); + } + catch (Exception e) { + throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass ); + } + } + + /** + * Returns true if the bean defines a property with the given name. + *

      + * The given name must be a String; if not, this method + * returns false. This method will also return false if the bean + * does not define a property with that name. + *

      + * Write-only properties will not be matched as the test operates against + * property read methods. + * + * @param name the name of the property to check + * @return false if the given name is null or is not a String; + * false if the bean does not define a property with that name; or + * true if the bean does define a property with that name + */ + public boolean containsKey(Object name) { + Method method = getReadMethod(name); + return method != null; + } + + /** + * Returns true if the bean defines a property whose current value is + * the given object. + * + * @param value the value to check + * @return false true if the bean has at least one property whose + * current value is that object, false otherwise + */ + public boolean containsValue(Object value) { + // use default implementation + return super.containsValue(value); + } + + /** + * Returns the value of the bean's property with the given name. + *

      + * The given name must be a {@link String} and must not be + * null; otherwise, this method returns null. + * If the bean defines a property with the given name, the value of + * that property is returned. Otherwise, null is + * returned. + *

      + * Write-only properties will not be matched as the test operates against + * property read methods. + * + * @param name the name of the property whose value to return + * @return the value of the property with that name + */ + public Object get(Object name) { + if ( bean != null ) { + Method method = getReadMethod( name ); + if ( method != null ) { + try { + return method.invoke( bean, NULL_ARGUMENTS ); + } + catch ( IllegalAccessException e ) { + logWarn( e ); + } + catch ( IllegalArgumentException e ) { + logWarn( e ); + } + catch ( InvocationTargetException e ) { + logWarn( e ); + } + catch ( NullPointerException e ) { + logWarn( e ); + } + } + } + return null; + } + + /** + * Sets the bean property with the given name to the given value. + * + * @param name the name of the property to set + * @param value the value to set that property to + * @return the previous value of that property + * @throws IllegalArgumentException if the given name is null; + * if the given name is not a {@link String}; if the bean doesn't + * define a property with that name; or if the bean property with + * that name is read-only + * @throws ClassCastException if an error occurs creating the method args + */ + public Object put(String name, Object value) throws IllegalArgumentException, ClassCastException { + if ( bean != null ) { + Object oldValue = get( name ); + Method method = getWriteMethod( name ); + if ( method == null ) { + throw new IllegalArgumentException( "The bean of type: "+ + bean.getClass().getName() + " has no property called: " + name ); + } + try { + Object[] arguments = createWriteMethodArguments( method, value ); + method.invoke( bean, arguments ); + + Object newValue = get( name ); + firePropertyChange( name, oldValue, newValue ); + } + catch ( InvocationTargetException e ) { + logInfo( e ); + throw new IllegalArgumentException( e.getMessage() ); + } + catch ( IllegalAccessException e ) { + logInfo( e ); + throw new IllegalArgumentException( e.getMessage() ); + } + return oldValue; + } + return null; + } + + /** + * Returns the number of properties defined by the bean. + * + * @return the number of properties defined by the bean + */ + public int size() { + return readMethods.size(); + } + + + /** + * Get the keys for this BeanMap. + *

      + * Write-only properties are not included in the returned set of + * property names, although it is possible to set their value and to get + * their type. + * + * @return BeanMap keys. The Set returned by this method is not + * modifiable. + */ + public Set keySet() { + return readMethods.keySet(); + } + + /** + * Gets a Set of MapEntry objects that are the mappings for this BeanMap. + *

      + * Each MapEntry can be set but not removed. + * + * @return the unmodifiable set of mappings + */ + public Set> entrySet() { + return new AbstractSet>() { + public Iterator iterator() { + return entryIterator(); + } + public int size() { + return BeanMap.this.readMethods.size(); + } + }; + } + + /** + * Returns the values for the BeanMap. + * + * @return values for the BeanMap. The returned collection is not + * modifiable. + */ + public Collection values() { + ArrayList answer = new ArrayList( readMethods.size() ); + for ( Iterator iter = valueIterator(); iter.hasNext(); ) { + answer.add( iter.next() ); + } + return answer; + } + + + // Helper methods + //------------------------------------------------------------------------- + + /** + * Returns the type of the property with the given name. + * + * @param name the name of the property + * @return the type of the property, or null if no such + * property exists + */ + public Class getType(String name) { + return (Class) types.get( name ); + } + + /** + * Convenience method for getting an iterator over the keys. + *

      + * Write-only properties will not be returned in the iterator. + * + * @return an iterator over the keys + */ + public Iterator keyIterator() { + return readMethods.keySet().iterator(); + } + + /** + * Convenience method for getting an iterator over the values. + * + * @return an iterator over the values + */ + public Iterator valueIterator() { + final Iterator iter = keyIterator(); + return new Iterator() { + public boolean hasNext() { + return iter.hasNext(); + } + public Object next() { + Object key = iter.next(); + return get(key); + } + public void remove() { + throw new UnsupportedOperationException( "remove() not supported for BeanMap" ); + } + }; + } + + /** + * Convenience method for getting an iterator over the entries. + * + * @return an iterator over the entries + */ + public Iterator entryIterator() { + final Iterator iter = keyIterator(); + return new Iterator() { + public boolean hasNext() { + return iter.hasNext(); + } + public Entry next() { + String key = iter.next(); + Object value = get(key); + return new Entry( BeanMap.this, key, value ); + } + public void remove() { + throw new UnsupportedOperationException( "remove() not supported for BeanMap" ); + } + }; + } + + + // Properties + //------------------------------------------------------------------------- + + /** + * Returns the bean currently being operated on. The return value may + * be null if this map is empty. + * + * @return the bean being operated on by this map + */ + public Object getBean() { + return bean; + } + + /** + * Sets the bean to be operated on by this map. The given value may + * be null, in which case this map will be empty. + * + * @param newBean the new bean to operate on + */ + public void setBean( Object newBean ) { + bean = newBean; + reinitialise(); + } + + /** + * Returns the accessor for the property with the given name. + * + * @param name the name of the property + * @return the accessor method for the property, or null + */ + public Method getReadMethod(String name) { + return (Method) readMethods.get(name); + } + + /** + * Returns the mutator for the property with the given name. + * + * @param name the name of the property + * @return the mutator method for the property, or null + */ + public Method getWriteMethod(String name) { + return (Method) writeMethods.get(name); + } + + + // Implementation methods + //------------------------------------------------------------------------- + + /** + * Returns the accessor for the property with the given name. + * + * @param name the name of the property + * @return null if the name is null; null if the name is not a + * {@link String}; null if no such property exists; or the accessor + * method for that property + */ + protected Method getReadMethod( Object name ) { + return (Method) readMethods.get( name ); + } + + /** + * Returns the mutator for the property with the given name. + * + * @param name the name of the + * @return null if the name is null; null if the name is not a + * {@link String}; null if no such property exists; null if the + * property is read-only; or the mutator method for that property + */ + protected Method getWriteMethod( Object name ) { + return (Method) writeMethods.get( name ); + } + + /** + * Reinitializes this bean. Called during {@link #setBean(Object)}. + * Does introspection to find properties. + */ + protected void reinitialise() { + readMethods.clear(); + writeMethods.clear(); + types.clear(); + initialise(); + } + + private void initialise() { + if(getBean() == null) { + return; + } + + Class beanClass = getBean().getClass(); + try { + //BeanInfo beanInfo = Introspector.getBeanInfo( bean, null ); + BeanInfo beanInfo = Introspector.getBeanInfo( beanClass ); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + if ( propertyDescriptors != null ) { + for ( int i = 0; i < propertyDescriptors.length; i++ ) { + PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; + if ( propertyDescriptor != null ) { + String name = propertyDescriptor.getName(); + Method readMethod = propertyDescriptor.getReadMethod(); + Method writeMethod = propertyDescriptor.getWriteMethod(); + Class aType = propertyDescriptor.getPropertyType(); + + if ( readMethod != null ) { + readMethods.put( name, readMethod ); + } + if ( writeMethod != null ) { + writeMethods.put( name, writeMethod ); + } + types.put( name, aType ); + } + } + } + } + catch ( IntrospectionException e ) { + logWarn( e ); + } + } + + /** + * Called during a successful {@link #put(Object,Object)} operation. + * Default implementation does nothing. Override to be notified of + * property changes in the bean caused by this map. + * + * @param key the name of the property that changed + * @param oldValue the old value for that property + * @param newValue the new value for that property + */ + protected void firePropertyChange( Object key, Object oldValue, Object newValue ) { + } + + // Implementation classes + //------------------------------------------------------------------------- + + /** + * Map entry used by {@link BeanMap}. + */ + protected static class Entry implements Map.Entry { + private BeanMap owner; + + private String key; + + private Object value; + + /** + * Constructs a new Entry. + * + * @param owner the BeanMap this entry belongs to + * @param key the key for this entry + * @param value the value for this entry + */ + protected Entry( BeanMap owner, String key, Object value ) { + this.owner = owner; + this.key = key; + this.value = value; + } + + /** + * Sets the value. + * + * @param value the new value for the entry + * @return the old value for the entry + */ + public Object setValue(Object value) { + String key = getKey(); + Object oldValue = owner.get( key ); + + owner.put( key, value ); + Object newValue = owner.get( key ); + this.value = newValue; + return oldValue; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Object getValue() { + return value; + } + } + + /** + * Creates an array of parameters to pass to the given mutator method. + * If the given object is not the right type to pass to the method + * directly, it will be converted using {@link #convertType(Class,Object)}. + * + * @param method the mutator method + * @param value the value to pass to the mutator method + * @return an array containing one object that is either the given value + * or a applyed value + * @throws IllegalAccessException if {@link #convertType(Class,Object)} + * raises it + * @throws IllegalArgumentException if any other exception is raised + * by {@link #convertType(Class,Object)} + * @throws ClassCastException if an error occurs creating the method args + */ + protected Object[] createWriteMethodArguments( Method method, Object value ) + throws IllegalAccessException, ClassCastException { + try { + if ( value != null ) { + Class[] types = method.getParameterTypes(); + if ( types != null && types.length > 0 ) { + Class paramType = types[0]; + if ( ! paramType.isAssignableFrom( value.getClass() ) ) { + value = convertType( paramType, value ); + } + } + } + Object[] answer = { value }; + return answer; + } + catch ( InvocationTargetException e ) { + logInfo( e ); + throw new IllegalArgumentException( e.getMessage() ); + } + catch ( InstantiationException e ) { + logInfo( e ); + throw new IllegalArgumentException( e.getMessage() ); + } + } + + /** + * Converts the given value to the given type. First, reflection is + * is used to find a public constructor declared by the given class + * that takes one argument, which must be the precise type of the + * given value. If such a constructor is found, a new object is + * created by passing the given value to that constructor, and the + * newly constructed object is returned.

      + * + * If no such constructor exists, and the given type is a primitive + * type, then the given value is converted to a string using its + * {@link Object#toString() toString()} method, and that string is + * parsed into the correct primitive type using, for instance, + * {@link Integer#valueOf(String)} to convert the string into an + * int.

      + * + * If no special constructor exists and the given type is not a + * primitive type, this method returns the original value. + * + * @param newType the type to convert the value to + * @param value the value to convert + * @return the converted value + * @throws NumberFormatException if newType is a primitive type, and + * the string representation of the given value cannot be converted + * to that type + * @throws InstantiationException if the constructor found with + * reflection raises it + * @throws InvocationTargetException if the constructor found with + * reflection raises it + * @throws IllegalAccessException never + * @throws IllegalArgumentException never + */ + protected Object convertType( Class newType, Object value ) + throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + + // try call constructor + Class[] types = { value.getClass() }; + try { + Constructor constructor = newType.getConstructor( types ); + Object[] arguments = { value }; + return constructor.newInstance( arguments ); + } + catch ( NoSuchMethodException e ) { + // try using the applyers + Function applyer = getTypeFunction( newType ); + if ( applyer != null ) { + return applyer.apply( value ); + } + return value; + } + } + + /** + * Returns a applyer for the given primitive type. + * + * @param aType the primitive type whose applyer to return + * @return a applyer that will convert strings into that type, + * or null if the given type is not a primitive type + */ + protected Function getTypeFunction( Class aType ) { + return (Function) typeFunctions.get( aType ); + } + + /** + * Logs the given exception to System.out. Used to display + * warnings while accessing/mutating the bean. + * + * @param ex the exception to log + */ + protected void logInfo(Exception ex) { + // Deliberately do not use LOG4J or Commons Logging to avoid dependencies + System.out.println( "INFO: Exception: " + ex ); + } + + /** + * Logs the given exception to System.err. Used to display + * errors while accessing/mutating the bean. + * + * @param ex the exception to log + */ + protected void logWarn(Exception ex) { + // Deliberately do not use LOG4J or Commons Logging to avoid dependencies + System.out.println( "WARN: Exception: " + ex ); + ex.printStackTrace(); + } +} diff --git a/querydsl-core/src/main/java/com/mysema/util/FileUtils.java b/querydsl-core/src/main/java/com/mysema/util/FileUtils.java new file mode 100644 index 000000000..b67ecfde8 --- /dev/null +++ b/querydsl-core/src/main/java/com/mysema/util/FileUtils.java @@ -0,0 +1,19 @@ +package com.mysema.util; + +import java.io.File; +import java.io.IOException; + +public abstract class FileUtils { + + public static void delete(File file) throws IOException { + if (file.isDirectory()) { + for (File f : file.listFiles()) { + delete(f); + } + } + file.delete(); + } + + private FileUtils() {} + +}