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

Syntax Error in Generated Model Code for Media Relationships with JsonApiX #73

Open
LakshmanSagar opened this issue Dec 19, 2024 · 2 comments
Assignees
Labels
bug Something isn't working

Comments

@LakshmanSagar
Copy link

📖 Description

Description

When using the JsonApiX library to process models containing @HasMany relationships (e.g., mediaRelationships), the generated model class contains invalid Kotlin syntax. Specifically, the equality comparison == true in the .filter block causes a compilation error.

ℹ️ Environment

Environment

Android Studio Ladybug | 2024.2.1 Patch 3
Build #AI-242.23339.11.2421.12700392, built on November 22, 2024
Runtime version: 21.0.3+-12282718-b509.11 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Toolkit: sun.awt.windows.WToolkit
Windows 10.0
Kotlin plugin: K2 mode (Beta)
GC: G1 Young Generation, G1 Concurrent GC, G1 Old Generation
Memory: 4096M
Cores: 4
Registry:
ide.instant.shutdown=false
ide.experimental.ui=true
i18n.locale=

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("com.infinum.jsonapix:core:1.0.3")
kapt("com.infinum.jsonapix:processor:1.0.3")
implementation("com.infinum.jsonapix:retrofit:1.0.3")

💣 Steps to reproduce

Reproduction Steps

  1. Define the following models:
Models
@JsonApiX(type = "anime")
@Serializable
data class Anime(
    val id: String,
    val canonicalTitle: String,
    val averageRating: String? = null,
    val episodeCount: Int? = null,
    val posterImage: PosterImage? = null,
    @HasMany(type = "characters")
    val characters: List<Character>? = null,
    @HasMany(type = "genres")
    val genres: List<Genre>? = null,
    @HasMany(type = "categories")
    val categories: List<Category>? = null,
    @HasMany(type = "mediaRelationships")
    val mediaRelationships: List<MediaRelationship>? = null
)

@JsonApiX(type = "characters")
@Serializable
data class Character(
    val id: String,
    val name: String,
    val image: CharacterImage? = null
)

@JsonApiX(type = "genres")
@Serializable
data class Genre(
    val id: String,
    val name: String
)

@JsonApiX(type = "categories")
@Serializable
data class Category(
    val id: String,
    val title: String
)

@JsonApiX(type = "mediaRelationships")
@Serializable
data class MediaRelationship(
    val id: String,
    val role: String? = null,
    @HasOne(type = "anime")
    val destination: Anime? = null
)

@Serializable
data class PosterImage(
    val small: String? = null,
    val medium: String? = null,
    val large: String? = null,
    val original: String? = null
)

@Serializable
data class CharacterImage(
    val tiny: String? = null,
    val small: String? = null,
    val large: String? = null,
    val original: String? = null
)
  1. Call the API with this request:
https://kitsu.io/api/edge/anime/7442?include=characters.character,genres,categories,mediaRelationships.destination&fields[anime]=canonicalTitle,averageRating,episodeCount,posterImage&fields[characters]=name,image&fields[genres]=name&fields[categories]=title&fields[mediaRelationships]=role
  1. Process the API response using JsonApiX.

🔧 Expected behavior

Expected Behavior

The generated ResourceObject_Anime class should compile successfully and map the mediaRelationships correctly.

Actual Behavior

The generated code includes invalid syntax in the mediaRelationships mapping logic, causing the following error:

e: file:///.../ResourceObject_Anime.kt:59:9 Syntax error: Expecting an element.
Generated Code Snippet
mediaRelationships = relationships?.let { safeRelationships ->
    included?.filter {
        safeRelationships.mediaRelationships?.data?.contains(ResourceIdentifier(it.type, it.id))
    == true
    }?.map { it.original(included) }.takeIf { it?.isNotEmpty() == true } as
    kotlin.collections.List<com.app.animebyte.model.MediaRelationship>?
}

This occurs because of the redundant == true comparison within the .filter block.


Full Generated Class

@Serializable
@SerialName(value = "ResourceObject_anime")
public class ResourceObject_Anime(
  @SerialName(value = "type")
  override val type: String = "anime",
  @SerialName(value = "id")
  override val id: String = "0",
  @SerialName(value = "attributes")
  override val attributes: Attributes_Anime? = null,
  @SerialName(value = "relationships")
  override val relationships: Relationships_Anime? = null,
  @SerialName(value = "links")
  override val links: DefaultLinks? = null,
  @SerialName(value = "meta")
  override val meta: Meta? = null,
) : ResourceObject<Anime> {
  override fun original(included: List<ResourceObject<Any>>?): Anime {
    val tempOriginal = com.app.animebyte.model.Anime(
      averageRating = attributes?.averageRating,
      canonicalTitle = requireNotNull(attributes?.canonicalTitle, "canonicalTitle"),
      episodeCount = attributes?.episodeCount,
      id = requireNotNull(attributes?.id, "id"),
      posterImage = attributes?.posterImage,
      categories = relationships?.let { safeRelationships ->
        included?.filter {
          safeRelationships.categories?.data?.contains(ResourceIdentifier(it.type, it.id)) == true
        }?.map { it.original(included) }.takeIf { it?.isNotEmpty() == true } as
        kotlin.collections.List<com.app.animebyte.model.Category>?
      },
      characters = relationships?.let { safeRelationships ->
        included?.filter {
          safeRelationships.characters?.data?.contains(ResourceIdentifier(it.type, it.id)) == true
        }?.map { it.original(included) }.takeIf { it?.isNotEmpty() == true } as
        kotlin.collections.List<com.app.animebyte.model.Character>?
      },
      genres = relationships?.let { safeRelationships ->
        included?.filter {
          safeRelationships.genres?.data?.contains(ResourceIdentifier(it.type, it.id)) == true
        }?.map { it.original(included) }.takeIf { it?.isNotEmpty() == true } as
        kotlin.collections.List<com.app.animebyte.model.Genre>?
      },
      mediaRelationships = relationships?.let { safeRelationships ->
        included?.filter {
          safeRelationships.mediaRelationships?.data?.contains(ResourceIdentifier(it.type, it.id))
        == true
        }?.map { it.original(included) }.takeIf { it?.isNotEmpty() == true } as
        kotlin.collections.List<com.app.animebyte.model.MediaRelationship>?
      },
    )
    (tempOriginal as? JsonApiModel)?.let {
      tempOriginal.setType(type)
      tempOriginal.setId(id)
    }
    return tempOriginal
  }
}

📄 Additional information

Suggested Fix

  1. Remove the redundant == true comparison in the generated code.
  2. Ensure that HasMany and HasOne relationships are resolved correctly and consistently in the generated models.
@LakshmanSagar LakshmanSagar added the bug Something isn't working label Dec 19, 2024
@thisAAY
Copy link
Collaborator

thisAAY commented Dec 19, 2024

Hi @LakshmanSagar
I will look into it this week
Thanks for reporting

@LakshmanSagar
Copy link
Author

Sure. Thanks for your efforts and for creating this wonderful library which makes developers' lives easier.

Anyways, when I press backspace before the generated code == (where the warning is being shown), the warning disappears in the generated code as well. I'm not sure why the generated code doesn’t have issues with the genre and character classes but only produces this bug with the media relationships class.

I'm also new to using the JSON-API standard, so I apologize if I made any mistakes. Please feel free to guide me if I made any errors in setting up the model classes.🙏🏻🤞🏻

@thisAAY thisAAY self-assigned this Dec 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants