Kotlinpoet: Ommitting redundant `public` modifier from generated types and properties - kotlin

Is there any way to omit the redundant public modifier from types and properties generated via
KotlinPoet's TypeSpec.Builder and PropertySpec.Builder respectively?

Egor's answer above is the correct one. There is no way to omit redundant public modifiers in KotlinPoet, and there is good reason for that.
However, all those (unnecessary in my case) warnings were getting to my nerves and I had to find some way to get rid of them. What I finally came up with, is to suppress them in KotlinPoet-generated files.
Here's an extension for FileSpec.Builder that enables you to suppress warnings for a particular generated file.
internal fun FileSpec.Builder.suppressWarningTypes(vararg types: String) {
if (types.isEmpty()) {
return
}
val format = "%S,".repeat(types.count()).trimEnd(',')
addAnnotation(
AnnotationSpec.builder(ClassName("", "Suppress"))
.addMember(format, *types)
.build()
)
}
And here's an example of how to use it to get rid of the redundant visibility modifiers warning in generated files:
val fileBuilder = FileSpec.builder(myPackageName, myClassName)
fileBuilder.suppressWarningTypes("RedundantVisibilityModifier")
The extension also supports suppressing more than one warning types:
fileBuilder.suppressWarningTypes("RedundantVisibilityModifier", "USELESS_CAST")
Please note that I'm in no way suggesting that you should get rid of ALL the warnings that bother you in your generated code! Use this code carefully!

No, and no plans to support such functionality. If it's important for your use case to not have explicit public modifiers, a good solution would be to post-process the output with a script that removes them.

Related

How can I tell the Kotlin compiler that a Java method will never return null?

I don't or can't modify the Java source code. The goal to configure just the Kotlin compiler to know what is nullable and what isn't.
You can specify the type manually if you know something will never be null. For example, if you have the following Java code:
public static Foo test() {
return null;
}
and you call it in Kotlin like this:
val result = Foo.test()
then result will have a type of Foo! by default – which means it can be either Foo or Foo?.. the compiler doesn't have enough information to determine that.
However, you can force the type manually:
val result: Foo = Foo.test()
// use "result" as a non-nullable type
Of course, if at runtime that is not true, you'll get a NullPointerException.
For reference, please check the documentation.
I don't know of a way to configure the compiler for this, but IntelliJ IDEA has a feature that allows you to add annotations to code via an XML file called external annotations.
You can add the Jetbrains #Nullable and #NotNull annotations to library code, but when I've tried it, it only results in compiler warnings rather than errors when you use incorrect nullability in your code. These same annotations generate compiler errors when used directly in the source code. I don't know why there is a difference in behavior.
You can use extension functions for this. If you have a method String foo() in the class Test, you can define the extension function
fun Test.safeFoo(): String = this.foo()!!
The advantage is that the code is pretty obious.
The disadvantage of this approach is that you need to write a lot of boiler plate code. You also have to define the extension function in a place where all your modules or projects can see it. Also, writing that much code just to avoid !! feels like overkill.
It should also be possible to write a Kotlin compiler extension which generates them for you but the extension would need to know which methods never return null.

Should I use an explicit return type for a String variable in Kotlin?

In Kotlin, We can declare a string read-only variable with type assignment and without type assignment (inferred) as below.
val variable_name = "Hello world"
or
val variable_name: String = "Hello world"
I'm trying to figure out what is the best in Kotlin and why it is the best way. Any idea?
If this is a public variable, using an explicit return type is always a good idea.
It can make the code easier to read and use. This is why your IDE probably shows the return type anyway, even when you omit it from the code. It's less important for simple properties like yours where the return type is easy to see at a glance, but when the property or method is more than a few lines it makes much more difference.
It prevents you from accidentally changing the type. With an explicit return type, if you change the contents of the property so that it doesn't actually return the correct type, you'll get an immediate compile error in that method or property. With an implicit type, if you change the contents of the method you could see cascading errors throughout your code base, making it hard to find the source of the error.
It can actually speed up your IDE! See this blog post from the JetBrains team for more information.
For private variables, explicit return types are much less important, because the above points don't generally apply.
Personally either one works and for me nothing is wrong, but I would choose the later if this is a team project, where project size increase and feature inheritance(members leaving, new hiring or worse shuffling people) is probable. Also I consider the later as more of a courtesy.
There are situations where regardless of the dogma every member follows, such as clean architecture, design-patterns or clean-coding, bloated codes or files are always expected to occur in such big projects occasionally, so the later would help anyone especially new members to easily recognize at first glance what data type they are dealing with.
Again this this is not about right or wrong, as kotlin is created to be idiomatic, I think this is Autoboxing, it was done in kotlin for codes to be shorter and cleaner as few of its many promise, but again regardless of the language, sometimes its the developer's discretion to have a readable code or not.
This also applies with function return types, I always specify my function return types just so the "new guy" or any other developer will understand my function signatures right away, saving him tons of brain cells understanding whats going on.
fun isValidEmail() : Boolean = if (condition) true else false
fun getValidatedPerson(): Person = repository.getAuthenticatedPersonbyId(id)
fun getCurrentVisibleScreen(): #Composable ()-> Unit = composables.get()
fun getCurrentContext(): Context if (isActivity) activityContext else applicationContext

Why is my "List<String>" being interpreted as "List<String>?"

class Example(private val childrenByParent: HashMap<String, List<String>>) {
private val parents: List<String> = childrenByParent.keys.toList()
fun getChildrenCount(parentPosition: Int): Int {
return childrenByParent[parents[parentPosition]].size
// error, recommends using "?." or "!!"
}
}
The compiler won't let me call size directly but I don't understand why. There are no nullable types in sight.
If I let the compiler infer the type by doing this:
val infer = childrenByParent[parents[parentPosition]]
I can see that it assumes it's a List<String>?
It seems that I'm quite confused about nullability still. Would appreciate some help. I have a feeling I'm doing something incredibly dumb, but after some searching and testing I failed at fixing this.
I would like for this function to not use ?. or even worse, !!. Is it possible? At least, using HashMap and List<String>.
HashMap.get(Object) returns null when there is no element matching the key you provided, so its return type is effectively nullable, regardless of whether the values are or not.
So unfortunately you have to account for the case in which the key doesn't exist, so your choices are either implementing a case where it doesn't, or just declaring it as non-null with !! if you are sure the key exists.
Otherwise you can use HashMap.containsKey(String) to ensure the key exists and then you can be confident that using !! on the value won't result in a NullPointerException.
However as #gidds pointed out, this is not naturally thread-safe without some more work, so it might be best to just handle the case of the key not being in the map. Also I cannot actually think of many cases where you could be sure that key exists, in which a Map is the most appropriate data structure to use.
Also, even though this is not the case here, remember that nullability is just a feature of Kotlin, so when using some classes originally written in Java, whether an element is nullable or not is unknown. The IDE will usually represent this as Type! where the single ! tells you it is a platform type.

How to add additional methods to autocomplete in IntelliJ

When I'm coding using IntelliJ I frequently use the auto-completion as a way of speeding up my coding, however there are certain methods that it doesn't seem to suggest. One example is Collectors.toMap - it will suggest toSet, toColletion and toList when I type .collect but never toMap which means I need to type more.
As a 1st question, can I fix this behaviour? As a more general question, can I add my own custom code to be auto completed in these types of circumstance?
One trick which helps me out every time while trying to collect the stream is having a placeholder variable with the expected type. Something like:
// just a placeholder variable with proper types, which I can remove later!
Map<String, String> tempMapVariable = someCollection.stream()
.collect(
// here it will suggest the .toMap(...)
Collectors.toMap(i -> i.getKey(), i -> getValue())
);
Set<String> tempSetVariable = someCollection.stream()
.map(SomeCollection::mapperFn)
.collect(
// here it will suggest the .toSet()
Collectors.toSet()
);

Kotlin [1..n] constructor parameter

Is there a way to enforce 1..* parameters in Kotlin that will still allow the spread operator?
I've tried:
class Permission(
// 1..n compliance
accessiblePage: Webpage,
vararg accessiblePages: Webpage
) {
And that does enforce 1..*, but it also means that Permission(*pages) won't work, so that's a pretty awkward interface.
Is there an easy way to enforce 1..* without a runtime constructor error?
There is, unfortunately, no way to check this in Kotlin at compile time aside from the way you mentioned. Since vararg parameters are really just syntactic sugar for an array, your code is essentially
class Permission (
accessiblePage: Webpage,
accessiblePages: Array<Webpage>
)
So the question then becomes "Can you ensure that an array has at least one element in it at compile time?" For most languages, that's a clear no, although the Kotlin team did at one point experiment with it:
[C]urrently, Kotlin compiler doesn't collect static information about
collections size. FYI, at some point Kotlin team tried to collect such
information and use it for warnings about possible
IndexOutOfBoundException and stuff like that, but it was found that
there were a very little demand on such diagnostics in real-life
projects, so, given complexity of such analysis, it was abandoned[.]
(https://github.com/Kotlin/KEEP/issues/139#issuecomment-405551324)
It's possible that this metadata will be added at some point, but you shouldn't expect it soon.
That said, you could always combine a runtime check in the case of an Array with an overloaded signature in the case of varargs. This would mean that your vararg example would work the same, but passing an array to the function would subject it to a runtime check (you'd also not have to use the spread operator anymore):
class Permission (
accessiblePage: Webpage
vararg accessiblePages: Webpage
) {
constructor(accessiblePages: Array<Webpage>) {
require(accessiblePages.isNotEmpty()) {
"Must have at least one accessible page."
}
}
}
called like
val permission1 = Permission(Webpage(), Webpage())
val permission2 = Permission() // Would fail at compile time
val pages = arrayOf()
val permission3 = Permission(pages) // Would fail at runtime. Note also the lack of the spread operator.