Skip to content

Commit

Permalink
Merge pull request #231 from viartemev/add-micronaut-support
Browse files Browse the repository at this point in the history
Add micronaut support
  • Loading branch information
viartemev committed Dec 2, 2019
2 parents 1aa22a7 + 1399f8a commit 7825fbe
Show file tree
Hide file tree
Showing 15 changed files with 218 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ package com.viartemev.requestmapper.annotations

import com.intellij.psi.PsiAnnotation
import com.viartemev.requestmapper.RequestMappingItem
import com.viartemev.requestmapper.annotations.jaxrs.DELETE
import com.viartemev.requestmapper.annotations.jaxrs.GET
import com.viartemev.requestmapper.annotations.jaxrs.HEAD
import com.viartemev.requestmapper.annotations.jaxrs.OPTIONS
import com.viartemev.requestmapper.annotations.jaxrs.PATCH
import com.viartemev.requestmapper.annotations.jaxrs.POST
import com.viartemev.requestmapper.annotations.jaxrs.PUT
import com.viartemev.requestmapper.annotations.jaxrs.HEAD
import com.viartemev.requestmapper.annotations.jaxrs.DELETE
import com.viartemev.requestmapper.annotations.jaxrs.PATCH
import com.viartemev.requestmapper.annotations.micronaut.Delete
import com.viartemev.requestmapper.annotations.micronaut.Get
import com.viartemev.requestmapper.annotations.micronaut.Head
import com.viartemev.requestmapper.annotations.micronaut.Options
import com.viartemev.requestmapper.annotations.micronaut.Patch
import com.viartemev.requestmapper.annotations.micronaut.Post
import com.viartemev.requestmapper.annotations.micronaut.Put

import com.viartemev.requestmapper.annotations.spring.DeleteMapping
import com.viartemev.requestmapper.annotations.spring.GetMapping
import com.viartemev.requestmapper.annotations.spring.PatchMapping
Expand All @@ -28,13 +36,22 @@ interface MappingAnnotation {
PutMapping::class.java.simpleName,
PatchMapping::class.java.simpleName,
DeleteMapping::class.java.simpleName,

GET::class.java.simpleName,
PUT::class.java.simpleName,
POST::class.java.simpleName,
OPTIONS::class.java.simpleName,
HEAD::class.java.simpleName,
DELETE::class.java.simpleName,
PATCH::class.java.simpleName
PATCH::class.java.simpleName,

Delete::class.java.simpleName,
Get::class.java.simpleName,
Head::class.java.simpleName,
Options::class.java.simpleName,
Patch::class.java.simpleName,
Post::class.java.simpleName,
Put::class.java.simpleName
)

fun mappingAnnotation(annotationName: String, psiAnnotation: PsiAnnotation): MappingAnnotation {
Expand All @@ -45,13 +62,23 @@ interface MappingAnnotation {
PutMapping::class.java.simpleName -> PutMapping(psiAnnotation)
PatchMapping::class.java.simpleName -> PatchMapping(psiAnnotation)
DeleteMapping::class.java.simpleName -> DeleteMapping(psiAnnotation)

GET::class.java.simpleName -> GET(psiAnnotation)
PUT::class.java.simpleName -> PUT(psiAnnotation)
POST::class.java.simpleName -> POST(psiAnnotation)
OPTIONS::class.java.simpleName -> OPTIONS(psiAnnotation)
HEAD::class.java.simpleName -> HEAD(psiAnnotation)
DELETE::class.java.simpleName -> DELETE(psiAnnotation)
PATCH::class.java.simpleName -> PATCH(psiAnnotation)

Get::class.java.simpleName -> Get(psiAnnotation)
Put::class.java.simpleName -> Put(psiAnnotation)
Post::class.java.simpleName -> Post(psiAnnotation)
Options::class.java.simpleName -> Options(psiAnnotation)
Head::class.java.simpleName -> Head(psiAnnotation)
Delete::class.java.simpleName -> Delete(psiAnnotation)
Patch::class.java.simpleName -> Patch(psiAnnotation)

else -> UnknownAnnotation
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import com.intellij.psi.PsiReferenceExpression
abstract class BasePsiAnnotationValueVisitor : PsiAnnotationValueVisitor {

fun visit(annotation: PsiAnnotation, parameter: String): List<String> {
val attributeValue = annotation.findAttributeValue(parameter)
return when (attributeValue) {
return when (val attributeValue = annotation.findAttributeValue(parameter)) {
is PsiArrayInitializerMemberValue -> visitPsiArrayInitializerMemberValue(attributeValue)
is PsiReferenceExpression -> visitPsiReferenceExpression(attributeValue)
is PsiBinaryExpression -> visitPsiBinaryExpression(attributeValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ object PsiExpressionExtractor {
}

private fun extractPath(value: PsiReferenceExpression): String {
return value.resolve()?.let {
it
return value.resolve()?.let { psiElement: PsiElement ->
psiElement
.children
.asSequence()
.filter { it is PsiBinaryExpression || it is PsiLiteralExpression || it is PsiPolyadicExpression }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ abstract class JaxRsMappingAnnotation(
}

private fun extractParameterNameFromAnnotation(annotation: PsiAnnotation, defaultValue: String): String {
val pathVariableValue = annotation.findAttributeValue(ATTRIBUTE_NAME)
return when (pathVariableValue) {
return when (val pathVariableValue = annotation.findAttributeValue(ATTRIBUTE_NAME)) {
is PsiLiteralExpression -> {
val expression = extractExpression(pathVariableValue)
if (expression.isNotBlank()) expression else defaultValue
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Delete(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "DELETE"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Get(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "GET"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Head(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "HEAD"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiLiteralExpression
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReferenceExpression

import com.viartemev.requestmapper.RequestMappingItem
import com.viartemev.requestmapper.annotations.MappingAnnotation
import com.viartemev.requestmapper.annotations.PathAnnotation
import com.viartemev.requestmapper.annotations.UrlFormatter
import com.viartemev.requestmapper.annotations.extraction.PsiExpressionExtractor.extractExpression
import com.viartemev.requestmapper.model.Path
import com.viartemev.requestmapper.model.PathParameter
import com.viartemev.requestmapper.utils.fetchAnnotatedMethod
import com.viartemev.requestmapper.utils.unquote

abstract class MicronautMappingAnnotation(
val psiAnnotation: PsiAnnotation,
private val urlFormatter: UrlFormatter = MicronautUrlFormatter
) : MappingAnnotation {

override fun values(): List<RequestMappingItem> {
return fetchRequestMappingItem(psiAnnotation, psiAnnotation.fetchAnnotatedMethod(), extractMethod())
}

abstract fun extractMethod(): String

private fun fetchRequestMappingItem(annotation: PsiAnnotation, psiMethod: PsiMethod, method: String): List<RequestMappingItem> {
val classMapping = fetchMappingFromClass(psiMethod)
val methodMapping = fetchMappingFromMethod(annotation, psiMethod)
return listOf(RequestMappingItem(psiMethod, urlFormatter.format(classMapping, methodMapping), method))
}

private fun fetchMappingFromClass(psiMethod: PsiMethod): String {
return psiMethod
.containingClass
?.modifierList
?.annotations
?.flatMap { extractPathFromMicronautPsiAnnotations(it) }
?.firstOrNull() ?: ""
}

private fun extractPathFromMicronautPsiAnnotations(psiAnnotation: PsiAnnotation) = when (psiAnnotation.qualifiedName) {
CONTROLLER_ANNOTATION -> PathAnnotation(psiAnnotation).fetchMappings(ATTRIBUTE_NAME)
else -> emptyList()
}

private fun fetchMappingFromMethod(annotation: PsiAnnotation, method: PsiMethod): String {
val parametersNameWithType = method
.parameterList
.parameters
.mapNotNull {
PathParameter(it).extractParameterNameWithType(PATH_VARIABLE_ANNOTATION, ::extractParameterNameFromAnnotation)
?: Pair(it.name!!, it.type.presentableText.unquote())
}
.toMap()

return PathAnnotation(annotation).fetchMappings(ATTRIBUTE_NAME)
.map { Path(it).addPathVariablesTypes(parametersNameWithType).toFullPath() }
.firstOrNull() ?: ""
}

private fun extractParameterNameFromAnnotation(annotation: PsiAnnotation, defaultValue: String): String {
return when (val pathVariableValue = annotation.findAttributeValue(ATTRIBUTE_NAME)) {
is PsiLiteralExpression -> {
val expression = extractExpression(pathVariableValue)
if (expression.isNotBlank()) expression else defaultValue
}
is PsiReferenceExpression -> {
val expression = extractExpression(pathVariableValue)
if (expression.isNotBlank()) expression else defaultValue
}
else -> defaultValue
}
}

companion object {
private const val CONTROLLER_ANNOTATION = "io.micronaut.http.annotation.Controller"
private const val ATTRIBUTE_NAME = "value"
private const val PATH_VARIABLE_ANNOTATION = "io.micronaut.http.annotation.PathVariable"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.viartemev.requestmapper.annotations.UrlFormatter
import com.viartemev.requestmapper.utils.dropFirstEmptyStringIfExists

object MicronautUrlFormatter : UrlFormatter {

override fun format(classMapping: String, methodMapping: String, param: String): String {
val classPathSeq = classMapping.splitToSequence('/').filterNot { it.isBlank() }
val methodPathList = methodMapping.split('/').dropFirstEmptyStringIfExists()
return (classPathSeq + methodPathList).joinToString(separator = "/", prefix = "/")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Options(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "OPTIONS"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Patch(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "PATCH"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Post(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "POST"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.viartemev.requestmapper.annotations.micronaut

import com.intellij.psi.PsiAnnotation

class Put(psiAnnotation: PsiAnnotation) : MicronautMappingAnnotation(psiAnnotation) {

override fun extractMethod() = METHOD

companion object {
private const val METHOD = "PUT"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ abstract class SpringMappingAnnotation(

private fun fetchMapping(annotation: PsiAnnotation): List<String> {
val pathMapping = PathAnnotation(annotation).fetchMappings(PATH)
return if (!pathMapping.isEmpty()) pathMapping else {
return if (pathMapping.isNotEmpty()) pathMapping else {
val valueMapping = PathAnnotation(annotation).fetchMappings(VALUE)
if (valueMapping.isNotEmpty()) valueMapping else listOf("")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fun String.inCurlyBrackets(): Boolean = length >= 2 && first() == '{' && last()

fun String.unquoteCurlyBrackets(): String = if (this.inCurlyBrackets()) this.drop(1).dropLast(1) else this

fun String.addCurlyBrackets(): String = '{' + this + '}'
fun String.addCurlyBrackets(): String = "{$this}"

fun List<String>.dropFirstEmptyStringIfExists(): List<String> = if (this.isNotEmpty() && this.first().isEmpty()) this.drop(1) else this

Expand Down

0 comments on commit 7825fbe

Please sign in to comment.