浏览代码

EnumUtils - encode/decode String
LexicalCast - EnumSet <-> String

Ranides Atterwim 13 年之前
父节点
当前提交
be349a04ff

+ 1 - 1
pom.xml

@@ -4,7 +4,7 @@
 
     <groupId>net.ranides</groupId>
     <artifactId>assira</artifactId>
-    <version>0.60.2</version>
+    <version>0.60.3</version>
     <packaging>jar</packaging>
 
     <name>assira</name>

+ 10 - 10
src/main/java/net/ranides/assira/collection/ArrayUtils.java

@@ -277,7 +277,7 @@ public final class ArrayUtils {
      */
     @Meta.Unsafe
     @SuppressWarnings("unchecked")
-    public static <T> List<T> wrap(Class<?> clazz, Object array) { // @test (assira)
+    public static <T> List<T> wrap(Class<?> clazz, Object array) {
         if(array instanceof List) {
             return (List<T>)array;
         }
@@ -475,12 +475,12 @@ public final class ArrayUtils {
      */
     @SuppressWarnings("unchecked")
     public static <Auto> Auto shift(Object values) {
-        if(values == null) {  // @test (assira)
+        if(values == null) {
             throw new EmptyCollectionException();
         }
         UnsafeArrayAccess access = UnsafeArrayAccess.forObject(values);
         int n = access.length(values);
-        if(n == 0) { // @test (assira)
+        if(n == 0) {
             throw new EmptyCollectionException();
         }
         Object value = access.get(values, 0);
@@ -511,12 +511,12 @@ public final class ArrayUtils {
      */
     @SuppressWarnings("unchecked")
     public static <Auto> Auto unshift(Object values) {
-        if(values == null) { // @test (assira)
+        if(values == null) {
             throw new EmptyCollectionException();
         }
         UnsafeArrayAccess access = UnsafeArrayAccess.forObject(values);
         int n = access.length(values);
-        if(n == 0) { // @test (assira)
+        if(n == 0) {
             throw new EmptyCollectionException();
         }
         Object value = access.get(values, n-1);
@@ -633,7 +633,7 @@ public final class ArrayUtils {
      * mogła się zmieścić w tablicy podanej jako docelowa.
      */
     @SuppressWarnings("unchecked")
-    public static <T> T[] arraycopy(T[] target, Object[] source) { // @test (assira)
+    public static <T> T[] arraycopy(T[] target, Object[] source) {
         Class<T> component = (Class<T>)target.getClass().getComponentType();
         T[] result = target.length >= source.length ? target : makeT(component, source.length);
 
@@ -664,7 +664,7 @@ public final class ArrayUtils {
      * @return
      */
     @SuppressWarnings({"unchecked", "SuspiciousSystemArraycopy"})
-    public static <ArrayT> ArrayT arraycopy(ArrayT source) { // @test (assira)
+    public static <ArrayT> ArrayT arraycopy(ArrayT source) {
         int size = size(source);
         Object target = make(source.getClass(), size);
         System.arraycopy(source, 0, target, 0, size);
@@ -680,7 +680,7 @@ public final class ArrayUtils {
      * @return pozycja elementu równego {@code value} lub {@code -1},
      * jeśli nie znaleziono elementu.
      */
-    public static <T> int indexOf(T[] array, T value) { // @test (assira)
+    public static <T> int indexOf(T[] array, T value) {
         if( array == null) {
             return -1;
         }
@@ -697,11 +697,11 @@ public final class ArrayUtils {
      * @param value
      * @return
      */
-    public static <T> boolean contains(T[] array, T value) { // @test (assira)
+    public static <T> boolean contains(T[] array, T value) {
         return indexOf(array, value) >= 0;
     }
 
-    public static <S> Object[] apply(S[] values, Function<?,S> function) { // @test (assira)
+    public static <S> Object[] apply(S[] values, Function<?,S> function) {
         if(values == null) {
             return values;
         }

+ 2 - 2
src/main/java/net/ranides/assira/collection/ByteArrays.java

@@ -49,7 +49,7 @@ public final class ByteArrays {
      * @param array2
      * @return
      */
-    public static boolean isEqual(byte[] array1, byte[] array2) { // @test (assira)
+    public static boolean isEqual(byte[] array1, byte[] array2) {
         if (array1==array2) {
             return true;
         }
@@ -74,7 +74,7 @@ public final class ByteArrays {
      * @param array2
      * @return
      */
-    public static boolean isEqual(int size, byte[] array1, byte[] array2) { // @test (assira)
+    public static boolean isEqual(int size, byte[] array1, byte[] array2) {
         if (array1==array2) {
             return true;
         }

+ 37 - 7
src/main/java/net/ranides/assira/enums/EnumUtils.java

@@ -15,15 +15,20 @@ import java.util.Map;
 import java.util.Set;
 import net.ranides.assira.math.Bitwise;
 import net.ranides.assira.reflection.BeanModel;
+import net.ranides.assira.text.StrBuilder;
+import net.ranides.assira.trace.AdvLogger;
+import net.ranides.assira.trace.LoggerUtils;
 
 /**
  * Klasa, która utworzona na rzecz konkretnego typu {@code enum} umożliwa dokonanie
  * pewnych sprawdzeń za pomocą inspekcji
- * @param <E> 
+ * @param <E>
  * @author ranides
  */
 public final class EnumUtils {
-    
+
+    private static final AdvLogger LOGGER = LoggerUtils.getLogger();
+
     private EnumUtils() {
         // utility class
     }
@@ -31,7 +36,7 @@ public final class EnumUtils {
     /**
      * Pobiera dla wszystkich wartości zadeklarowanych w typie enum atrybut JavaBeans,
      * i tworzy mapę, w której kluczem jest wartość atrybutu, a wartością stała
-     * enum. Jeśli uzyskane klucze nie tworzą unikalnego zbioru, to rzucany jest 
+     * enum. Jeśli uzyskane klucze nie tworzą unikalnego zbioru, to rzucany jest
      * wyjątek {@link EnumDuplicateError}
      * @param property
      * @throws EnumDuplicateKey
@@ -52,7 +57,7 @@ public final class EnumUtils {
         }
         return map;
     }
-    
+
     public static <K, E extends Enum<E> & EnumHash<K>> Map<K, E> mapHash(Class<E> eenum) {
         Map<K, E> map = new HashMap<K, E>();
 
@@ -66,7 +71,7 @@ public final class EnumUtils {
         }
         return map;
     }
-    
+
     public static <E extends Enum<E> & EnumInt> Map<Integer, E> mapInt(Class<E> eenum) {
         Map<Integer, E> map = new HashMap<Integer, E>();
 
@@ -80,7 +85,7 @@ public final class EnumUtils {
         }
         return map;
     }
-    
+
     public static <E extends Enum<E> & EnumInt> int encodeInt(Set<E> values) {
         int result = 0;
         for(E item : values) {
@@ -88,7 +93,7 @@ public final class EnumUtils {
         }
         return result;
     }
-    
+
     public static <E extends Enum<E> & EnumInt> EnumSet<E> decodeInt(Class<E> eenum, int flags) {
         EnumSet<E> result = EnumSet.noneOf(eenum);
         for(E item : eenum.getEnumConstants()) {
@@ -97,4 +102,29 @@ public final class EnumUtils {
         return result;
     }
 
+    public static <E extends Enum<E>> String encodeText(Set<E> values) {
+        StrBuilder result = new StrBuilder();
+        result.list(" ");
+        for(E item : values) {
+            result.item().append(item.name());
+        }
+        return result.toString();
+    }
+
+    public static <E extends Enum<E>> EnumSet<E> decodeText(Class<E> eenum, String text) {
+        EnumSet<E> result = EnumSet.noneOf(eenum);
+        for(String item : text.split("[ ,]+")) {
+            try {
+                result.add(Enum.valueOf(eenum, item));
+            } catch(IllegalArgumentException _1) {
+                try {
+                    result.add(Enum.valueOf(eenum, item));
+                } catch(IllegalArgumentException _2) {
+                    LOGGER.fwarn("Unknown enum value: %s : %s", eenum.getName(), item);
+                }
+            }
+        }
+        return result;
+    }
+
 }

+ 45 - 44
src/main/java/net/ranides/assira/text/LexicalCast.java

@@ -14,6 +14,7 @@ import java.io.IOException;
 import java.util.*;
 import java.util.Map.Entry;
 import net.ranides.assira.collection.ArrayUtils;
+import net.ranides.assira.enums.EnumUtils;
 import net.ranides.assira.generic.Function;
 import net.ranides.assira.generic.TypeToken;
 import net.ranides.assira.time.DateQuickFormat;
@@ -21,41 +22,41 @@ import net.ranides.assira.time.DateQuickFormat;
 /**
  * Klasa używana tylko do prezentowania obiektów jako tekst bardziej
  * reprezentatywnie niż za pomocą wbudowanych metod "toString".
- * 
+ *
  * @author ranides
  */
 public final class LexicalCast {
-    
+
     private static final TypeFactory TYPE_FACTORY = TypeFactory.defaultInstance();
     private static final ObjectMapper MAPPER;
-    
+
     static {
         MAPPER = new ObjectMapper();
         MAPPER.configure(SerializationFeature.INDENT_OUTPUT, true);
     }
 
     private LexicalCast() { }
-    
+
     public static final Function<String, Object> SIMPLE =  new SimpleFunction();
 
     public static <T> List<String> asList(Iterable<T> values) {
         return asList(values, SIMPLE);
     }
-    
+
     public static <T> List<String> asList(Iterable<T> values, Function<String,? super T> converter) {
         List<String> result = makeList(values);
         for(T value : values) { result.add( converter.apply(value) ); }
         return result;
     }
-    
+
     public static <T> List<String> asList(T[] values) {
         return asList(ArrayUtils.wrap(values));
     }
-    
+
     public static <T> List<String> asList(T[] values, Function<String,? super T> converter) {
         return asList(ArrayUtils.wrap(values), converter);
     }
-    
+
     public static <K,V> List<String> asList(Map<K,V> map) {
         List<String> result = new ArrayList<String>(map.size());
         for(Entry<K,V> entry : map.entrySet()) {
@@ -63,7 +64,7 @@ public final class LexicalCast {
         }
         return result;
     }
-    
+
     public static <K,V> List<String> asList(Map<K,V> map, Function<String,Entry<K,V>> converter) {
         List<String> result = new ArrayList<String>(map.size());
         for(Entry<K,V> entry : map.entrySet()) {
@@ -71,7 +72,7 @@ public final class LexicalCast {
         }
         return result;
     }
-    
+
     private static <T> List<String> makeList(Iterable<T> values) {
         if( values instanceof Collection) {
             return new ArrayList<String>( ((Collection)values).size() );
@@ -79,13 +80,13 @@ public final class LexicalCast {
             return new LinkedList<String>();
         }
     }
-    
-/* ************************************************************************** */    
+
+/* ************************************************************************** */
 
     public static <K,V> String asText(Map<K,V> map) {
         return StringUtils.join(asList(map), "\n");
     }
-    
+
     public static String asText(Collection<?> values) {
         List<String> list = asList(values, new FromObject(){
             @Override
@@ -95,13 +96,13 @@ public final class LexicalCast {
         });
         return StringUtils.join(list, "\n");
     }
-    
+
     public static <T> String apply(T value) {
         return SIMPLE.apply(value);
     }
-    
-/* ************************************************************************** */  
-    
+
+/* ************************************************************************** */
+
     public static String object2json(Object value) throws LexicalCastException {
         try {
             return MAPPER.writeValueAsString(value);
@@ -109,7 +110,7 @@ public final class LexicalCast {
             throw new LexicalCastException(value.getClass()+" cannot be converted to JSON", cause);
         }
     }
-    
+
     public static <T> T json2object(String value, Class<T> clazz) throws LexicalCastException {
         try {
             return MAPPER.readValue(value, clazz);
@@ -117,7 +118,7 @@ public final class LexicalCast {
             throw new LexicalCastException(clazz + " cannot be created from JSON", cause);
         }
     }
-    
+
     @SuppressWarnings("unchecked")
     public static <T> T json2object(String value, TypeToken<T> token) throws LexicalCastException {
         try {
@@ -126,19 +127,19 @@ public final class LexicalCast {
             throw new LexicalCastException(token + " cannot be created from JSON", cause);
         }
     }
-    
+
     @SuppressWarnings("unchecked")
     public static <T> T cast(Object value, Class<T> clazz) throws ClassCastException {
         return (T)rawCast(value, null, clazz);
     }
-    
+
     @SuppressWarnings("unchecked")
     public static <T> T cast(Object value, TypeToken<T> token) throws LexicalCastException {
         return (T)rawCast(value, token, TYPE_FACTORY.constructType( token.type() ).getRawClass());
     }
-    
+
     @SuppressWarnings("PMD")
-    private static  Object rawCast(Object value, TypeToken<?> token, Class<?> clazz) {
+    private static Object rawCast(Object value, TypeToken<?> token, Class<?> clazz) {
         // brak konwersji null
         if(value==null) {
             return null;
@@ -146,12 +147,20 @@ public final class LexicalCast {
         if(clazz.equals(value.getClass()) && clazz.getTypeParameters().length==0) {
             return value;
         }
+        // konwersja EnumSet<?> -> String
+        if( value instanceof EnumSet && clazz.equals(String.class) ) {
+            return EnumUtils.encodeText((Set)value);
+        }
         // konwersja Bool -> String
         if(value instanceof Boolean && clazz.equals(String.class) ) {
             return ((Boolean)value).toString();
         }
         // najpopularniejsze konwersje String -> Number / Bool / char[]
         if(value instanceof String) {
+            // konwersja String -> Set<Enum<?>>
+            if( EnumSet.class.isAssignableFrom(clazz) ) {
+                return EnumUtils.decodeText((Class)token.params()[0].rawType(), (String)value );
+            }
             if( clazz.equals(long.class) || clazz.equals(Long.class)) {
                 return Double.valueOf((String)value).longValue();
             }
@@ -209,27 +218,19 @@ public final class LexicalCast {
             error.initCause(cause);
             throw error;
         }
-        
-    }
-    
-    public static <E extends Enum<E>> EnumSet<E> splitEnum(Class<E> clazz, String values) throws IllegalArgumentException {
-        EnumSet<E> result = EnumSet.noneOf(clazz);
-        for(String mode : values.split(" ")) {
-            if(Strings.isAssigned(mode)) { result.add( Enum.valueOf(clazz, mode) ); }
-        }
-        return result;
+
     }
-    
-/* ************************************************************************** */  
-    
-    private static class SimpleFunction implements Function<String, Object> { 
-        
+
+/* ************************************************************************** */
+
+    private static class SimpleFunction implements Function<String, Object> {
+
         @SuppressWarnings({"PMD.NPathComplexity", "PMD.CyclomaticComplexity"})
         @Override
         public String apply(Object value) {
             if(value == null) {
                 return "";
-            } 
+            }
             if( value instanceof String  || value instanceof Character ) {
                 return StringCompiler.quote(value);
             }
@@ -254,19 +255,19 @@ public final class LexicalCast {
             return value.toString();
         }
     }
-    
-    public static abstract class FromObject implements Function<String, Object> { 
+
+    public static abstract class FromObject implements Function<String, Object> {
     }
-    
+
     public static abstract class FromEntry<K,V> implements Function<String, Entry<K,V>> {
-        
+
         public abstract String apply(K key, V value);
 
         @Override
         public String apply(Entry<K, V> source) {
             return apply(source.getKey(), source.getValue());
         }
-        
+
     }
-    
+
 }

+ 12 - 0
src/test/java/net/ranides/assira/text/LexicalCastTest.java

@@ -14,6 +14,7 @@ import net.ranides.assira.collection.SetUtils;
 import net.ranides.assira.generic.Function;
 import net.ranides.assira.generic.TypeToken;
 import net.ranides.assira.generic.ValueUtils;
+import net.ranides.assira.io.FileFilter.AcceptMode;
 import net.ranides.assira.math.HashHelper;
 import org.junit.Test;
 import static org.junit.Assert.*;
@@ -443,6 +444,17 @@ public class LexicalCastTest extends SimpleBenchmark {
         return c;
     }
 
+    @Test
+    public void testEnumSet() {
+        Set<AcceptMode> input = EnumSet.of(AcceptMode.ANY_FILE, AcceptMode.RECURSIVE, AcceptMode.FILE);
+
+        String text = LexicalCast.cast(input, String.class);
+
+        Set<AcceptMode> output = LexicalCast.cast(text, new TypeToken<EnumSet<AcceptMode>>(){} );
+
+        assertEquals(input, output);
+    }
+
     public static void main(String[] args) {
         Runner.main(LexicalCastTest.class, args);
     }