11package implicit
22
3+ import implicit.annotation.generator.GenericType
34import implicit.conversion.TypeConversion
45import implicit.decorator.*
56import implicit.exception.ImplicitException
67import implicit.exception.ImplicitValidationException
78import implicit.exception.ImplicitViolations
9+ import implicit.extension.findAnnotation
810import net.bytebuddy.ByteBuddy
911import net.bytebuddy.NamingStrategy
1012import net.bytebuddy.description.method.MethodDescription
@@ -18,6 +20,10 @@ import java.lang.reflect.Method
1820import java.util.concurrent.ConcurrentHashMap
1921import java.util.function.Function
2022import java.util.function.Supplier
23+ import java.util.stream.Collectors
24+ import kotlin.reflect.KClass
25+ import kotlin.streams.toList
26+
2127
2228class Implicit (val namingStrategy : (TypeDescription ) -> CharSequence ) {
2329
@@ -95,10 +101,12 @@ class Implicit(val namingStrategy: (TypeDescription) -> CharSequence) {
95101 val instance: T = instantiate(type, cache)
96102 val implicitViolations = getType(instance!! ).declaredMethods
97103 .filter { method -> isSetter(method) }
98- .fold(ImplicitViolations (listOf ())) { acc, entry ->
104+ .fold(ImplicitViolations (listOf ())) { acc, method ->
99105 try {
100- val field = getFieldNameFromSetterMethod(entry)
101- setMapValueInInstance(instance, entry, map[field])
106+
107+ val field = getFieldNameFromSetterMethod(method)
108+ val fieldValue = handleGenerics(type, method, map[field])
109+ setMapValueInInstance(instance, method, fieldValue)
102110 acc
103111 } catch (ex: ImplicitValidationException ) {
104112 ImplicitViolations (acc.violations.plus(ex))
@@ -123,6 +131,42 @@ class Implicit(val namingStrategy: (TypeDescription) -> CharSequence) {
123131 }
124132 }
125133
134+ private fun <T > handleGenerics (type : Class <T >, method : Method , value : Any? ): Any? {
135+ val valuesInACollection = convertToCollection(value)
136+ if (valuesInACollection!= null ) {
137+ val genericType = getGenericType(type, method)
138+ if (genericType!= null ){
139+ if (method.parameterTypes.first().isAssignableFrom(List ::class .java)) {
140+ return instantiateGenericNestedObject(valuesInACollection, genericType).toList()
141+ }
142+ if (method.parameterTypes.first().isAssignableFrom(Set ::class .java)) {
143+ return instantiateGenericNestedObject(valuesInACollection, genericType).collect(Collectors .toSet())
144+ }
145+ }
146+ }
147+ return value
148+ }
149+
150+ private fun convertToCollection (value : Any? ) : Collection <* >? {
151+ if (value!= null ){
152+ if (value is Collection <* >)
153+ return value
154+ else if (value is Array <* >)
155+ return value.toList()
156+ }
157+ return null
158+ }
159+
160+ private fun instantiateGenericNestedObject (value : Collection <* >, clazz : KClass <* >) = value.stream().map { instantiateNestedObject(clazz.java, it as Map <* , * >) }
161+
162+ private fun <T > getGenericType (type : Class <T >, method : Method ): KClass <* >? {
163+ return type.declaredMethods
164+ .filter { it.name == method.name }
165+ .filter { it.isAnnotationPresent(GenericType ::class .java) }
166+ .map { it.findAnnotation(GenericType ::class )!! .value }
167+ .firstOrNull()
168+ }
169+
126170 fun getFieldNameFromSetterMethod (setter : Method ): String = setter.name.substring(3 ).decapitalize()
127171 fun isNestedImplicitObject (objClass : Class <* >, fieldValue : Any? ): Boolean = objClass.isInterface && objClass != Map ::class .java && fieldValue is Map <* , * >
128172 fun isSetter (method : Method ): Boolean = method.name.startsWith(" set" )
0 commit comments