Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-534 Add ktlint for Kotlin and refactor codebase to utilize Kotlin idioms #536

Merged
merged 5 commits into from
Oct 5, 2020
Merged

GH-534 Add ktlint for Kotlin and refactor codebase to utilize Kotlin idioms #536

merged 5 commits into from
Oct 5, 2020

Conversation

junlarsen
Copy link
Contributor

@junlarsen junlarsen commented Oct 5, 2020

Closes #534

This patch adds https://github.com/pinterest/ktlint, a linting tool to keep code style across the project consistent as well as refactoring parts of the codebase to use idiomatic Kotlin as discussed in #534

Ktlint is executed through Maven with mvn antrun:run@ktlint-format.

Further refactoring

A lot of the types in the codebase are nullable (makes sense as this comes from java land) and because I'm not too familiar with the project itself it's difficult to tell if any nullable types are actually nullable or not. If these types can be made non-null we can ensure further type safety, if this is not the case, there should be fallback values as the functions the values are passed into doesn't expect a nullable value.

Anything inside /test/old_tests has not been touched.

Copy link
Contributor Author

@junlarsen junlarsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a code review containing all of the notable changes, remaining changes are mostly ktlint autoformatting indentation and spacing

Comment on lines -61 to +64
val messageSource = ReloadableResourceBundleMessageSource()
messageSource.setBasename("classpath:messages")
messageSource.setDefaultEncoding("UTF-8")
return messageSource
return ReloadableResourceBundleMessageSource().also {
it.setBasename("classpath:message")
it.setDefaultEncoding("UTF-8")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kotlin has a set of Scope Functions which are neat and especially useful for initialization or modification on newly created objects which makes the code easier to grasp.

https://kotlinlang.org/docs/reference/scope-functions.html

return ResponseEntity.ok(mapOf("access_token" to authenticationTokenCreator.create(authentication)))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Java's Collections.singletonMap may be replaced with a mapOf(x to y). This also removes the explicit generic arguments.

import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

internal class AuthenticationEntryPoint : AuthenticationEntryPoint {

@Throws(IOException::class)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kotlin code does not require @Throws tags for anything and I believe the app should run and compile fine without them being present.

These tags are only used if third-party java code is written using the compiled kotlin jar, something which is probably not going to happen as this is a standalone project.

Comment on lines +29 to +31
data class OAuth(
var redirectUrls: List<String?> = ArrayList()
}
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are POJOs, which can and should be moved into data classes

Comment on lines -54 to -58
if (authorizationHeaderContent != null && authorizationHeaderContent.startsWith(bearer)) {
return authorizationHeaderContent.substring(bearer.length)
return if (authorizationHeaderContent != null && authorizationHeaderContent.startsWith(bearer)) {
authorizationHeaderContent.substring(bearer.length)
} else {
null
}

return null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May lift the if into the return

Comment on lines +54 to +61
user = if (user != null) {
if (providerName != user.provider) {
throw RuntimeException("Looks like you're already signed up with " + user.provider + " account.")
}

user = updateExistingUser(user, userDetails)
updateExistingUser(user, userDetails)
} else {
user = createNewUser(userRequest, userDetails)
createNewUser(userRequest, userDetails)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user lifted out of if statement

Comment on lines +86 to +90
user.apply {
name = userDetails.name
displayName = userDetails.displayName ?: StringUtils.EMPTY
avatar = userDetails.avatar ?: StringUtils.EMPTY
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to aforementioned .also for newly created objects, in this case we use .apply

Comment on lines -39 to +53
abstract class AbstractCrudController<S : CrudOperationsService<T, ID>, T : IdentifiableEntity<ID>, ID, U : AbstractDto<T>, C : AbstractDto<T>>(
protected open val service: S
) {

companion object {
private const val SPEL_EXPRESSION = "(isAuthenticated() && principal.user.identifier.equals(#id)) || hasAuthority('ADMIN')"
}
abstract class AbstractCrudController<S, T, ID, U, C>(
protected open val service: S
) where
S : CrudOperationsService<T, ID>,
T : IdentifiableEntity<ID>,
U : AbstractDto<T>,
C : AbstractDto<T> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kotlin has where constraits which do the same job as the former generic parameter declaration, but it's appended after the class signature in its own block, making the generic statement easier to grasp.

Comment on lines +24 to -30
return try {
return ObjectMapper().writer().writeValueAsString(this)
} catch (e: JsonProcessingException) {
e.printStackTrace()
null
}

return null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the try-catch block into the return

Comment on lines -39 to +46
if (cookies != null && cookies.isNotEmpty()) {
for (cookie in cookies) {
if (cookieName == cookie.name) {
return Optional.of(cookie)
}
}
val foundCookie = cookies?.let { cookie ->
cookie.firstOrNull { it.name == cookieName }
}

return Optional.empty()
return foundCookie?.let { Optional.of(it) }
?: Optional.empty()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just like Java streams, there are plenty of methods on the Kotlin Collections library which can reduce the above loop into a more condensed set of operations

@junlarsen junlarsen marked this pull request as ready for review October 5, 2020 16:49
@dzikoysk
Copy link
Member

dzikoysk commented Oct 5, 2020

Looks great, also thanks for all of these comments that clarify the intentions! ❤️

  • The OAuth2 implementation is kinda disliking any changes, so its updates require a dedicated investigation. I think we should let it be for now
  • The old_tests should be migrated in another issue anyway. A lot of these classes base on Mockito, which is not really a good practice. I've created a new issue which addresses this topic Replace Mockito based tests with better unit tests in Groovy #537

@dzikoysk dzikoysk changed the title Add ktlint for Kotlin and refactor codebase to utilize Kotlin idioms GH-534 Add ktlint for Kotlin and refactor codebase to utilize Kotlin idioms Oct 5, 2020
@dzikoysk dzikoysk merged commit efa3ebc into panda-lang:master Oct 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor sources after Java to Kotlin conversion
2 participants