Skip to content

Commit a644ba6

Browse files
fixing some Json related bugs, small refactoring, intoNew can now handle
generics in some cases, and AutoProt and UniversalProt/SelfSerial can too. This greatly increases the Json capabilities.
1 parent bea917d commit a644ba6

File tree

8 files changed

+429
-204
lines changed

8 files changed

+429
-204
lines changed

SerialX-core/src/main/java/org/ugp/serialx/GenericScope.java

Lines changed: 81 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static org.ugp.serialx.Utils.Instantiate;
44

55
import java.io.Serializable;
6+
import java.lang.reflect.Type;
67
import java.util.ArrayList;
78
import java.util.Arrays;
89
import java.util.Collection;
@@ -273,8 +274,8 @@ public <V extends ValT> V get(KeyT variableKey)
273274
@SuppressWarnings("unchecked")
274275
public <V extends ValT> V get(KeyT variableKey, V defaultValue)
275276
{
276-
V obj = (V) variables().get(variableKey);
277-
if (obj == null)
277+
V obj;
278+
if ((obj = (V) variables().get(variableKey)) == null)
278279
return defaultValue;
279280
return obj;
280281
}
@@ -342,7 +343,7 @@ public <V extends ValT> V get(KeyT... pathToValue)
342343
*
343344
* @since 1.3.7
344345
*/
345-
public <V extends ValT> V get(KeyT variableKey, Class<V> cls, V defaultValue) throws Exception
346+
public <V extends ValT> V get(KeyT variableKey, Class<? extends V> cls, V defaultValue) throws Exception
346347
{
347348
V obj = get(variableKey, defaultValue);
348349
if (obj != null && obj.getClass() == cls)
@@ -477,7 +478,7 @@ public boolean addAll(@SuppressWarnings("unchecked") ValT... values)
477478
* @since 1.3.7
478479
*/
479480
@Override
480-
public boolean containsAll(Collection<?> values)
481+
public boolean containsAll(Collection<?> values)
481482
{
482483
return values().containsAll(values);
483484
}
@@ -550,36 +551,41 @@ public <K, V> GenericScope<K, V> getGenericScope(K... pathToScope)
550551
}
551552

552553
/**
553-
* @param objClass | Object of class to create.
554+
* @param type | Class of object to create (may or may not support other implementations of {@link Type}).
554555
*
555-
* @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}!
556+
* @return Object of type constructed from this scopes independent values using protocol for given class or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}!
556557
*
557558
* @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}!
558559
*
559560
* @since 1.2.5
560561
*/
561-
public <T> T toObject(Class<T> objClass) throws Exception
562+
public <T> T toObject(Type type) throws Exception
562563
{
563-
return toObject(objClass, SerializationProtocol.REGISTRY);
564+
return toObject(type, SerializationProtocol.REGISTRY);
564565
}
565566

566567
/**
567-
* @param objClass | Object of class to create using protocols.
568+
* @param type | Class of object to create using protocols (may or may not support other implementations of {@link Type}).
568569
* @param protocolsToUse | Registry of protocols to use.
569570
*
570-
* @return Object of objClass constructed from this scopes independent values using protocol for objClass or null if there was no protocol found in {@link Serializer#PROTOCOL_REGISTRY}!
571+
* @return Object of class constructed from this scopes independent values using protocol for given class or null if there was no protocol found in protocolsToUse!
571572
*
572573
* @throws Exception | Exception if Exception occurred in {@link SerializationProtocol#unserialize(Class, Object...)}!
573574
*
574575
* @since 1.3.2
575576
*/
576-
public <T> T toObject(Class<T> objClass, ProtocolRegistry protocolsToUse) throws Exception
577+
@SuppressWarnings("unchecked")
578+
public <T> T toObject(Type type, ProtocolRegistry protocolsToUse) throws Exception
577579
{
578-
SerializationProtocol<T> pro = protocolsToUse == null ? null : protocolsToUse.GetProtocolFor(objClass, SerializationProtocol.MODE_DESERIALIZE);
579-
if (pro != null)
580+
if (protocolsToUse == null)
581+
return null;
582+
583+
Class<T> objClass;
584+
SerializationProtocol<T> pro;
585+
if ((pro = protocolsToUse.GetProtocolFor(objClass = (Class<T>) type, SerializationProtocol.MODE_DESERIALIZE)) != null)
580586
{
581-
T obj = pro.unserialize(objClass, this.variablesCount() > 0 ? new Object[] {this} : this.toArray());
582-
if (obj != null)
587+
T obj;
588+
if ((obj = pro.unserialize(objClass, variablesCount() > 0 ? new Object[] {this} : toArray())) != null)
583589
return obj;
584590
}
585591
return null;
@@ -588,7 +594,7 @@ public <T> T toObject(Class<T> objClass, ProtocolRegistry protocolsToUse) throws
588594
/**
589595
* @param predicate | Predicate object with filter condition in test method!
590596
*
591-
* @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included!
597+
* @return Scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included!
592598
*
593599
* @since 1.2.5
594600
*/
@@ -603,14 +609,14 @@ public GenericScope<KeyT, ValT> filter(Predicate<ValT> predicate)
603609
* If sub-scope is empty after filtration it will not be included in result!
604610
* Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})!
605611
*
606-
* @return Original scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away!
612+
* @return Scope after filtration using inserted predicate! If some object can't be casted to {@link Predicate#test(Object)} argument, it will be treated as invalid and will be filtered away!
607613
*
608614
* @since 1.2.5
609615
*/
610616
@SuppressWarnings("unchecked")
611617
public GenericScope<KeyT, ValT> filter(Predicate<ValT> predicate, boolean includeSubScopes)
612618
{
613-
return (GenericScope<KeyT, ValT>) transform(new Function<ValT, Object>()
619+
return (GenericScope<KeyT, ValT>) transform(new Function<ValT, Object>()
614620
{
615621
@Override
616622
public Object apply(ValT t)
@@ -623,7 +629,7 @@ public Object apply(ValT t)
623629
/**
624630
* @param trans | Function to transform objects of this scope!
625631
*
626-
* @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included!
632+
* @return Scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away! Sub-scopes are not included!
627633
*
628634
* @since 1.2.5
629635
*/
@@ -638,7 +644,7 @@ public <V> GenericScope<KeyT, V> transform(Function<ValT, V> trans)
638644
* If sub-scope is empty after transformation it will not be included in result!
639645
* Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})!
640646
*
641-
* @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away!
647+
* @return Scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away!
642648
*
643649
* @since 1.2.5
644650
*/
@@ -648,41 +654,40 @@ public <V> GenericScope<KeyT, V> transform(Function<ValT, V> trans, boolean incl
648654
if (trans == null || isEmpty())
649655
return (GenericScope<KeyT, V>) this;
650656

651-
List<V> fltVals = map(trans, includeSubScopes);
652-
LinkedHashMap<KeyT, V> fltVars = new LinkedHashMap<>();
653-
657+
LinkedHashMap<KeyT, V> mappedVars = new LinkedHashMap<>();
654658
for (Entry<KeyT, ValT> ent : this.varEntrySet())
655659
try
656660
{
657661
Object obj = ent.getValue();
658-
if (obj instanceof GenericScope && includeSubScopes)
662+
if (includeSubScopes && obj instanceof GenericScope)
659663
{
660664
GenericScope<?, V> sc = ((GenericScope<?, ValT>) obj).transform(trans, includeSubScopes);
661665
if (!sc.isEmpty())
662-
fltVars.put(ent.getKey(), (V) sc);
666+
mappedVars.put(ent.getKey(), (V) sc);
663667
}
664668
else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID)
665-
fltVars.put(ent.getKey(), trans.apply((ValT) obj));
669+
mappedVars.put(ent.getKey(), trans.apply((ValT) obj));
666670
}
667671
catch (ClassCastException e)
668672
{}
669673

670-
try
674+
List<V> mappedVals = map(trans, includeSubScopes);
675+
try
671676
{
672677
GenericScope<KeyT, V> clone = Instantiate(getClass());
673-
clone.values = fltVals;
674-
clone.variables = fltVars;
678+
clone.values = mappedVals;
679+
clone.variables = mappedVars;
675680
clone.parent = getParent();
676681
return clone;
677682
}
678683
catch (Exception e)
679684
{
680-
return new GenericScope<>(fltVars, fltVals, getParent());
685+
return new GenericScope<>(mappedVars, mappedVals, getParent());
681686
}
682687
}
683688

684689
/**
685-
* @param trans | Function to transform objects of this scope!
690+
* @param trans | Function to transform independent objects of this scope!
686691
*
687692
* @return Original scope after transformation using inserted function! If some object can't be casted to {@link Function#apply(Object)} argument, it will be treated as invalid and will be filtered away!
688693
*
@@ -694,7 +699,7 @@ public <V> List<V> map(Function<ValT, V> trans)
694699
}
695700

696701
/**
697-
* @param trans | Function to transform objects of this scope!
702+
* @param trans | Function to transform independent objects of this scope!
698703
* @param includeSubScopes | If true transformation will be also applied on sub-scopes, if false sub-scopes will be treated as other things (parsed in to {@link Function#apply(Object)}).
699704
* If sub-scope is empty after transformation it will not be included in result!
700705
* Note: Remember that this will work only when this scope generically allows to store other scopes inside (when ValT is base class of {@link GenericScope})!
@@ -706,23 +711,50 @@ public <V> List<V> map(Function<ValT, V> trans)
706711
@SuppressWarnings("unchecked")
707712
public <V> List<V> map(Function<ValT, V> trans, boolean includeSubScopes)
708713
{
709-
List<V> fltVals = new ArrayList<>();
710-
for (Object obj : this)
714+
// List<V> mapped = new ArrayList<>(size());
715+
// for (Object obj : this)
716+
// try
717+
// {
718+
// if (obj instanceof GenericScope && includeSubScopes)
719+
// {
720+
// GenericScope<?, V> sc = (GenericScope<?, V>) ((GenericScope<?, ValT>) obj).map(trans, includeSubScopes);
721+
// if (!sc.isEmpty())
722+
// mapped.add((V) sc);
723+
// }
724+
// else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID)
725+
// mapped.add((V) obj);
726+
// }
727+
// catch (ClassCastException e)
728+
// {}
729+
730+
List<V> mapped = (List<V>) toValList();
731+
for (int i = valuesCount()-1; i >= 0; i--)
732+
{
711733
try
712734
{
713-
if (obj instanceof GenericScope && includeSubScopes)
735+
Object obj = mapped.get(i);
736+
if (includeSubScopes && obj instanceof GenericScope)
714737
{
715-
GenericScope<?, V> sc = ((GenericScope<?, ValT>) obj).transform(trans, includeSubScopes);
738+
GenericScope<?, V> sc = (GenericScope<?, V>) ((GenericScope<?, ValT>) obj).map(trans, includeSubScopes);
716739
if (!sc.isEmpty())
717-
fltVals.add((V) sc);
740+
{
741+
mapped.set(i, (V) sc);
742+
continue;
743+
}
718744
}
719745
else if ((obj = trans.apply((ValT) obj)) != DataParser.VOID)
720-
fltVals.add((V) obj);
746+
{
747+
mapped.set(i, (V) obj);
748+
continue;
749+
}
721750
}
722-
catch (ClassCastException e)
751+
catch (ClassCastException e)
723752
{}
753+
754+
mapped.remove(i);
755+
}
724756

725-
return fltVals;
757+
return mapped;
726758
}
727759

728760
/**
@@ -857,21 +889,23 @@ public boolean isEmpty()
857889
}
858890

859891
/**
860-
* @return The parent scope of this scope or null if this scope has no parent such as default one in file.
892+
* @return The parent scope of this scope or null if this scope has no parent such as default one in file.<br>
893+
* Note: This may or may not be always null based on the way this scope was instantiated...
861894
*
862895
* @since 1.2.0
863896
*/
864897
public <T extends GenericScope<?, ?>> T getParent()
865898
{
866-
return getParent(1);
899+
return getParent(1);
867900
}
868901

869902
/**
870903
* @param depth | Positive number representing how many times will this method call itself... <br> For example 0 or less = this, 1 = parent, 2 = parentOfParent (parent.getParent()) and so on...
871904
* If you want to get the root parent (the one that has no parent), simply put a big number as depth. 99 should be enough!
872905
*
873906
* @return The parent scope based on depth or null if this scope has no parent which means its already root (default one in file).
874-
* If depth was bigger than 1, null will be never returned, last not null parent will be returned instead!<br>
907+
* If depth was bigger than 1, null will not be returned, last not null parent will be returned instead!<br>
908+
* Note: This may or may not be always null based on the way this scope was instantiated...
875909
*
876910
* @since 1.3.2
877911
*/
@@ -888,7 +922,7 @@ public boolean isEmpty()
888922
}
889923

890924
/**
891-
* @return New {@link LinkedHashMap} with variables of this a in defined order! Key is a KeyT of variable and value is its value! <br>
925+
* @return New {@link LinkedHashMap} with variables of this a in defined order! Key is a KeyT of variable and value is its value!<br>
892926
* Modifying this map will not affect this GenericScope object!
893927
*
894928
* @since 1.2.0
@@ -900,7 +934,8 @@ public boolean isEmpty()
900934

901935
/**
902936
* @return New {@link ArrayList} with independent values of this {@link GenericScope}. These values have nothing to do with values of variables, they are independent!
903-
* Modifying this list will not affect this GenericScope object!
937+
* Modifying this list will not affect this GenericScope object!<br>
938+
* Note: Returning other {@link List} implementations than {@link ArrayList} (or other collection that stores elements in "array-like fashion") may result in serious performance implications! Queues or LinkedLists are the prime examples to avoid!
904939
*
905940
* @since 1.2.0
906941
*/
@@ -1056,7 +1091,7 @@ public static <K, V, S extends GenericScope<K, V>> S intoBidirectional(S scopeTo
10561091
* @since 1.3.7
10571092
*/
10581093
@SuppressWarnings("unchecked")
1059-
public static <K, V> Map<K, V> mapKvArray(Map<K, V> map, Object... kVkVkV)
1094+
public static <K, V, M extends Map<K, V>> M mapKvArray(M map, Object... kVkVkV)
10601095
{
10611096
for (int i = 1; i < kVkVkV.length; i+=2)
10621097
map.put((K) kVkVkV[i-1], (V) kVkVkV[i]);

0 commit comments

Comments
 (0)