https://kotlinlang.org logo
#announcements
Title
# announcements
d

Dave Jensen

03/09/2020, 7:01 AM
I have a weird scenario and I was wondering if Kotlin has any language features that would make the solution more straightforward? I have a poorly designed 3rd party Java API that we must use. That library has the exact same class, let’s call it
Headers
, in a dozen or more packages but they do not implement an interface and all extend Object. I’ve struggling to come up with a solution that keeps the code DRY.
It’s literally something like 🙄
Copy code
package1.Headers
package2.Headers
...
package20.Headers
And they all have the exact same properties.
d

Dragan Stanojević - Nevidljivi

03/09/2020, 7:04 AM
You can use import alias like
import package1.Headers as <whatever name you like>
d

Dave Jensen

03/09/2020, 7:13 AM
I think that helps. 🤔
a

Amirul Zin

03/09/2020, 7:15 AM
Hmm. Doesn’t that practically make you have to copy paste everything again in the end? Maybe an intermediary reflection class is needed here to act as a proper double.
d

Dave Jensen

03/09/2020, 7:16 AM
Oof, the R-word.
I guess the only way to avoid reflection is annotations or a mapper library like MapStruct, which uses annotations.
I can’t really use a delegate in this situation either, right? The delegate still must implement the interface.
d

Dragan Stanojević - Nevidljivi

03/09/2020, 7:34 AM
I think you can look into Kotlin delegate features for that adapter/intermediary class. Kotlin might just help you avoid a lot of boilerplate code...
i

ianrumac

03/09/2020, 11:01 AM
maybe make a wrapper object that you pass the Header into and have that object obey an interface. you pass in the header as Any, have a setOf(Header1::class.java, Header2::class.java,etc…) which you check against if the object is it then cast into whatever class it is in the set and call the method.
d

Dave Jensen

03/09/2020, 4:18 PM
Well, the other half of the problem is that need to pass that header in like
package2.Client.send(package2.Headers, body, etc)
b

bbaldino

03/09/2020, 4:25 PM
Maybe you could define a common type in your lib, write extension functions to convert all the lib types into that type, and extension functions to convert from your type back into the specific types? Then you can bridge the gap by doing
MyCommonType.from(Package1.HeadersInstance)
and
<http://MyCommonType.to|MyCommonType.to><Package2.Headers>()
and write some code with reflection to create the right one?
d

Dave Jensen

03/09/2020, 4:27 PM
Yeah, that is similar the approach I'm experimenting with using MapStruct.
The idea is to have the mapper have mappings like
fun convertToHeaders2(headers: MyHeaders): package2.Headers
b

bbaldino

03/09/2020, 4:29 PM
If the params are all exactly the same, I think you could write a single
convert
function and pass the lib type you wanted via a generic and create it/fill it out using reflection
d

Dave Jensen

03/09/2020, 4:38 PM
Isn't there a performance hit with reflection? Now I'm wondering if I could generate some code to fill out the covert function without using reflection.
b

bbaldino

03/09/2020, 4:39 PM
You'd have to test if any performance hit was a deal breaker I guess. Are you talking about using
kotlinpoet
or something? Could also be a good way to do the original generation of all the methods without using reflection.
d

Daniel

03/09/2020, 6:33 PM
Personal opinion: Don't make an already complicated situation more complicated with reflection / code generation ect. Create a common class in your code and at the very end (where the api calls of the bad java lib are executed) map tthe class to headerXY. Basically wrap the whole lib. This way you can easily swap it out should you be able to some day
d

Dave Jensen

03/09/2020, 6:34 PM
We’d have to do that about 1 dozen times. 😕
b

bbaldino

03/09/2020, 6:35 PM
He's saying write a single wrapper around the "poorly designed 3rd party java API" that defines a custom type and does the translation, couldn't you just re-use that?
Or, do what 1 dozen times?
d

Dave Jensen

03/09/2020, 6:36 PM
There are about a dozen APIs we need to call. Each is in it’s own package, each has it’s own version of Headers.
d

Daniel

03/09/2020, 6:37 PM
I see no problem doing this a fixed amount of times. Then we have 12 map yourheader to libheaderX methods. Still less complicated than using reflection, code generation. Its different though when you expect the number of bad java headers to grow but still stay the same structure wise
b

bbaldino

03/09/2020, 6:38 PM
Ah gotcha. I feel like it'd be better to define a new common type and implement all of the to/from stuff then. Don't need to use reflection or code generation for it (or could do the code generation one time and commit the result, not re-generate it every time as part of the build or whatever)
d

Dave Jensen

03/09/2020, 6:38 PM
Copy code
package1.Api1.send(headers: package1.Headers)
package2.Api2.send(headers: package2.Headers)
package3.Api3.send(headers: package3.Headers)
package4.Api4.send(headers: package4.Headers)
package12.Api12.send(headers: package12.Headers)
I see no problem doing this a fixed amount of times.
It’s human error prone and IMO doesn’t buy much. Just pushing the problem into the wrapper. At least your code errors are all in one place.
d

Daniel

03/09/2020, 6:40 PM
Is the header implementation (bad java) unstable?
d

Dave Jensen

03/09/2020, 6:40 PM
Basically, I’m trying to avoid the same 12 lines of code over and over again.
Possibly, it’s generated from WSDL. 🤯
I really didn’t want to mention that piece because it might derail to conversation. So let’s not talk about WSDL. 😉
d

Daniel

03/09/2020, 6:44 PM
As always: personal opinion: The duplication here is "accidental" duplication. They may look the same now, but when you even say its unstable they may not look the same a few month out. Personally I see that its nicely dividable in api calls. Lets say you have a
MakeApi1Request
class which does something and then you have a
MakeApi2Request
class which does something different. That the mappers inside the classes which map from your business code to theirs are the same at the moment is not a big concern. This might change any moment. For example tomorrow they change api2.header and only this one. Then you only have to update one mapper
But of couse you can make a better asumption here, its only as I would do it given the current information 🙂
👍 1
9 Views