Types library can convert any object type into a required one, iterate any object, do structure transformations and wrap generic types.
Convert!
// fromStringstr = "1234";
Stringstr = "0b11010";
Stringstr = "0x46";
// tointnumber = Types.INTEGER.parse(str);
// fromdouble[] array = newdouble[] { 10.3, 8.4, 5.0 };
// toList<Float> list = AnyObject.of(array).asList(Types.FLOAT);
// fromList<String> strList = List.of(
"1234", "true",
"55", "false",
"10", "true"
);
// toMap<Integer, Boolean> intBooleanMap = newTypeOf<Map<Integer, Boolean>>(){}.parse(from);Iterate!
// single objectintnumber = 1234;
for (intelement : AnyIterable.<Integer>ofAny(number)) {
// do something
}
// arraydouble[] array = newdouble[] { 10.3, 8.4, 5.0 };
for (doubleelement : AnyIterable.of(array)) {
// do something
}
// listList<Float> list = List.of(10.3, 8.4, 5.0);
for (Floatelement : AnyIterable.of(list)) {
// do something
}
// mapMap<Integer, Boolean> to = Map.of(
1234, true,
55, false,
10, true
);
for (Map.Entry<Integer, Boolean> entry : AnyIterable.of(to)) {
// do something
}Wrap!
// Original String listList<String> stringList = List.of("1", "2", "3", "4");
// A view of original list as Integer listList<Integer> integerList = newWrappedList<>(stringList, TypeWrapper.of(Types.STRING, Types.INTEGER));
// So thisif (integerList.contains(3)) {
// ...
}
// Is the equivalent ofif (stringList.contains("3")) {
// ...
}How to implement Types library in your project.
This library contains the following artifacts:
types- The main project, a type parsing and iteration API.types-annotated- Annotated type parsing API.types-mapper- (experimental) Type mapping and transformation API.types-wrapper- Type wrapping API.
build.gradle
repositories {
mavenCentral()
}
dependencies {
implementation 'com.saicone:types:1.4.3'
}build.gradle.kts
repositories {
mavenCentral()
}
dependencies {
implementation("com.saicone:types:1.4.3")
}pom.xml
<dependencies>
<dependency>
<groupId>com.saicone</groupId>
<artifactId>types</artifactId>
<version>1.4.3</version>
<scope>compile</scope>
</dependency>
</dependencies>A "supported" type (for example) doesn't mean you can magically convert a Map<String, Integer> into Boolean,
every object type that you want to parse must have a minimum sense with the conversion or null will be return,
for example a "1.4" can be converted into any Number type.
Note
Any supported (primitive) object type can be returned as array value of its type.
Since primitive types cannot be explicitly null, they will be returned with a fallback value.
Click to show
charor'\0'booleanorBoolean.FALSEbyteorByte.MIN_VALUEshortorShort.MIN_VALUEintorInteger.MIN_VALUEfloatorFloat.MIN_VALUElongorLong.MIN_VALUEdoubleorDouble.MIN_VALUE
Well known Java objects and the accepted types to properly parse them.
Click to show
java.lang.Objectjava.lang.Stringjava.lang.Characterjava.lang.Booleantrue/falseoryes/nostring- Integer
0or1 - Decimal
0or between0and1
java.lang.Numberjava.lang.Bytejava.lang.Shortjava.lang.integerjava.lang.Floatjava.lang.Longjava.lang.Doublejava.lang.Class<?>- Qualified name, for example
some.package.for.MyClass - File path, for example
some/package/for/MyClass.classorC:\some\package\for\MyClass.java - Descriptor, for example
Lsome/package/for/MyClass; - Readable name, for example
int[][]
- Qualified name, for example
java.math.BigIntegerjava.math.BigDecimaljava.util.UUID- 36-length
String(with dashes)00000000-0000-0000-0000-000000000000 - 32-length
String(without dashes)00000000000000000000000000000000 - 4-length array (converted to int)
[000000000, 000000000, 000000000, 000000000] - 2-length array (converted to long)
[mostSigBits, leastSigBits]
- 36-length
java.util.regex.PatternStringStringwith a type annotated withPatternFlags
java.util.BitSetjava.net.URIStringURLFilePath
java.net.URLStringURIFilePath
java.io.FileStringseparated by/String[]Path
java.nio.file.PathStringseparated by/String[]File
java.time.DurationStringformated like15 MINUTES AND 30 SECONDSString[]formated like["15 MINUTES", "30 SECONDS"]
java.time.LocalDate- Epoch day
Long - 2-length array (converted to int)
[year, dayOfYear] - 3-length array (converted to int)
[year, month, day] - ISO-8601
String
- Epoch day
java.time.LocalTime- Seconds of day
Long - 2-length array (converted to int)
[hour, minute] - 3-length array (converted to int)
[hour, minute, second] - 4-length array (converted to int)
[hour, minute, second, nanoOfSecond] Stringformatted ashour:minute:second.nanoOfSecond, examples:"10:30","10:40:05","09:08:21.35"
- Seconds of day
java.time.LocalDateTime- Epoch seconds
Long - 5-length array (converted to int)
[year, month, day, hour, minute] - 6-length array (converted to int)
[year, month, day, hour, minute, second] - 7-length array (converted to int)
[year, month, day, hour, minute, second, nanoOfSecond] - ISO-8601
Stringseparated byTwith time formatted ashour:minute:second.nanoOfSecond
- Epoch seconds
Note
Any Number type can be parsed from:
- Enum, by extracting ordinal value
- Boolean
true = 1 | false = 0 - Decimal, for example
35 - Binary
0[bB][0-1], for example0b11010 - Hex
0[xX][0-9A-Fa-f], for example0x46 - Hex color
#[0-9A-Fa-f], for example#46 - Octal
0[oO]?[0-7], for example075or0o75
And also detect:
- Leading signs
+ - - Unsigned suffix
uorU - Number suffixes
b B s S i I f F l L d D
Typical Java objects with parameters.
Click to show
java.lang.Enum<?>- Name
String(case-insensitive) - Ordinal
Number - Other
Enumby extracting ordinal value.
- Name
java.util.Collection<E>- Can be any Java object that implementsCollectionjava.util.Map<K, V>- Can be any Java object that implementsMapMapIterableobject which its elements will be converted into keys and values.
(The type parameters E, K and V can be any supported type)
Functional Java objects to handle any type parser in a flexible way.
Click to show
java.util.Optional<E>- Contains parsed value, empty optional type is return when parse fails or throw exceptionjava.util.concurrent.CompletableFuture<E>- Maintain parse function into non-null return value (may throw NullPointerException)
(The type parameter E can be any supported type)
How to use Types library.
By default, Types library can convert 6 data types using 4 different methods.
- TypeParser - Make your own implementation of type conversion.
- Types - Same as TypeParser, but every parser is cached.
- AnyObject - Encapsulated object with methods to convert with Types or create one-time use TypeParser.
- TypeOf - Same as Types, but computes automatically the required type object parser (including generic objects).
Single objects:
Stringstr = "1234";
// Using TypeParserTypeParser<Double> parser = (object) -> Double.parseDouble(String.valueOf(object));
doublenumber = parser.parse(str);
// Using Types (Same as TypeParser, but extract first element of any iterable or array object)intnumber = Types.INTEGER.parse(str);
// Using AnyObjectfloatnumber = AnyObject.of(str).asFloat();
// Using TypeOfTypeOf<Long> type = newTypeOf<Long>(){};
longnumber = type.parse(str);Collections:
intnumber = 1234;
// Using TypeParserTypeParser<List<Integer>> parser = ListParser.of(Types.INTEGER);
List<Integer> list = parser.parse(number);
// Using TypesList<Double> list = Types.DOUBLE.list().parse(number);
// Using AnyObjectList<Float> list = AnyObject.of(number).asList(Types.FLOAT);
// Using TypeOfTypeOf<List<Long>> type = newTypeOf<List<Long>>(){};
List<Long> list = type.parse(number);Object Arrays:
Stringstr = "1234";
// Using TypeParserTypeParser<String[]> parser = ArrayParser.of(String.class);
String[] array = parser.parse(str);
// Using TypesInteger[] array = Types.INTEGER.array().parse(str);
// Using AnyObjectString[] array = AnyObject.of(str).asArray(Types.STRING);
// Using TypeOfTypeOf<Integer[]> type = newTypeOf<Integer[]>(){};
Integer[] array = type.parse(str);Primitive Arrays:
Stringstr = "1234";
// Using TypeParserTypeParser<int[]> parser = ArrayParser.of(int.class);
int[] array = parser.parse(str);
// Using Typesfloat[] array = Types.of(float.class).array().parse(str);
// Using AnyObjectdouble[] array = AnyObject.of(str).asArray(Types.of(double.class));
// Using TypeOfTypeOf<long[]> type = newTypeOf<long[]>(){};
long[] array = type.parse(str);Enums:
Stringstr = "VALUE_NAME";
// Using TypeParserTypeParser<MyEnum> parser = EnumParser.of(MyEnum.class);
MyEnumvalue = parser.parse(str);
// Using AnyObjectMyEnumvalue = AnyObject.of(str).asEnum(MyEnum.class);
// Using TypeOfTypeOf<MyEnum> type = newTypeOf<MyEnum>(){};
MyEnumvalue = type.parse(str);Maps:
Map<String, String> map = newHashMap<>();
map.put("1234", "true");
map.put("55", "false");
map.put("12", "true")
// Using TypeParserTypeParser<Map<Integer, Boolean>> parser = MapParser.of(Types.INTEGER, Types.BOOLEAN);
Map<Integer, Boolean> value = parser.parse(map);
// Using AnyObjectMap<Integer, Boolean> value = AnyObject.of(map).asMap(Types.INTEGER, Types.BOOLEAN, newHashMap<>());
// Using TypeOfTypeOf<Map<Integer, Boolean>> type = newTypeOf<Map<Integer, Boolean>>(){};
Map<Integer, Boolean> value = type.parse(map);Tip
If you create a TypeParser or use TypeOf is suggested to save as static final field.
How to iterate any object value.
// Single objectStringvalue = "text";
for (Stringstr : AnyIterable.<String>ofAny(value)) {
// do something
}
// Array / CollectionInteger[] value = newInteger[] { 1, 2, 3, 4 };
int[] value = newint[] { 1, 2, 3, 4 };
List<Integer> value = newArrayList<>();
for (inti : AnyIterable.of(value)) {
// do something
}
// MapMap<String, Integer> value = newHashMap<>();
for (Map.Entry<String, Integer> entry : AnyIterable.of(value)) {
// do something
}Type wrapping is a lazy object conversion that work in different dimensions using two types.
Type A: Is the base type of object, you can get it by unwrap the type B.
Type B: Is the type of object that wrap type A, in other words, to show A as B.
One dimension wrapper:
A one dimension TypeWrapper can be created using one type parser to wrap or unwrap any representation of a type.
TypeParser<Integer> parser = Types.INTEGER;
// Wrapper that only wrap objectsTypeWrapper<Integer, Integer> onlyWrap = TypeWrapper.wrap(parser);
// Wrapper that only unwrap objectsTypeWrapper<Integer, Integer> onlyUnwrap = TypeWrapper.unwrap(parser);
// ExampleList<Integer> list = newArrayList<>(List.of(1, 2, 3, 4));
// By only wrapping values you got a list that pass values to type wrapper for outgoing operations// Which is useless in this case since the wrapper doesn't make a value transformationList<Integer> integerList = newWrappedList<>(list, onlyWrap);
// This value was processed on wrapper, int this case any change was appliedinti = integerList.get(0);
// By only unwrapping values you got a list that accept any kind of object that can be converted to Integer on incoming operations// Which is useful to take advantage of type parsingList<Integer> integerList = newWrappedList<>(list, onlyUnwrap);
// In this case, the following operation is valid since any String is converted to Integerif (integerList.contains("2")) {
integerList.remove("1");
}Two dimension wrapper with cast:
A two dimension TypeWrapper can be created using one type parser to wrap type A or unwrap type B and expect that the other type must be obtained using a regular cast.
TypeParser<Long> parserA = Types.LONG;
TypeParser<Integer> parserB = Types.INTEGER;
// Wrapper that only wrap type A to show it as B// Meaning that you only need to provide a type parser to convert A to BTypeWrapper<Long, Integer> onlyWrap = TypeWrapper.wrap(parserB);
// Wrapper that only unwrap type B to return it as A// Meaning that you only need to provide a type parser to convert B to ATypeWrapper<Long, Integer> onlyUnwrap = TypeWrapper.unwrap(parserA);
// ExampleList<Long> longList = newArrayList<>(List.of(1L, 2L, 3L, 4L));
// By only wrapping values you got a list that show values as Integer for outgoing operations// And try to cast incoming values as Long for outgoing operationsList<Integer> integerList = newWrappedList<>(longList, onlyWrap);
// This value was converted from Longinti = integerList.get(0);
// By only unwrapping values you got a list that try to cast outgoing values as Integer for incoming operations// And accepts Long-representation values for incoming operations (for example, an Integer)List<Integer> integerList = newWrappedList<>(longList, onlyUnwrap);
// In this case the list accept any Long representation as wellif (integerList.contains(2L)) {
integerList.remove("1L");
}Two dimension wrapper:
A two dimension TypeWrapper can be created using one type parser to wrap type A and other type parser to unwrap type B.
TypeParser<Integer> parserA = Types.INTEGER;
TypeParser<String> parserB = Types.STRING;
// A wrapper that make Integers look like Strings by wrapping any String representation// And make String look like Integers by unwrapping any Integer representationTypeWrapper<Integer, String> wrapper = TypeWrapper.of(parserA, parserB);
// ExampleList<Integer> integerList = newArrayList<>(List.of(1, 2, 3, 4));
// By providing the wrapper, the Integer list will act as a String listList<String> stringList = newWrappedList<>(integerList, wrapper);
if (integerList.contains("2")) {
integerList.remove("1");
}How to register your own types.
// RegisterTypeParser<MyObject> parser = (object) -> {
// Convert into MyObject...
};
Types.put(MyObject.class, parser);
// UnregisterTypes.remove(MyObject.class);
// GetTypeParser<MyObject> parser = Types.of(MyObject.class);