jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.45k stars 4.02k forks source link

ManyToMany relationship causes exceeding maximum allowed document nesting depth #26378

Closed RafaelMonteiroExaud closed 2 months ago

RafaelMonteiroExaud commented 3 months ago
Overview of the issue

I have two entities with a ManyToMany relationship, defined like this in the JDL:

relationship ManyToMany {
  Post{tag(name)} to Tag{post}
}

If I create a Post, and then a Tag, and associate the Tag with the Post, or vice versa (Tag created first, and Post associated with Tag), then the frontend will load indefinitely their lists. Other entities still work fine, just these two are totally unusable. No ability to create new ones, view existing or modify them. In the dev console in the browser, the following error is thrown when viewing either of their pages:

Document nesting depth (1001) exceeds the maximum allowed (1000, from `StreamWriteConstraints.getMaxNestingDepth()`) (through reference chain: 
java.util.ArrayList[0]->com.okta.developer.blog.domain.Post["tags"]->java.util.LinkedHashSet[0]->com.okta.developer.blog.domain.Tag["posts"]
->java.util.LinkedHashSet[0]->com.okta.developer.blog.domain.Post["tags"]...

This is repeated hundreds of times more in the error.

Motivation for or Use Case

I'm investigating JHipster for use in a project, and was faced with this problem, which seems quite a severe one, as Many to Many relationships are to be used in the project, which makes it unusable.

Reproduce the error

When following the JHipster Mini Book, in the microservices section a JDL is provided. I have slightly modified it (mostly to fix User relationship since 8.0 and removed the Kubernetes part), and ran the following command to create the project: jhipster jdl apps.jdl --monorepository --workspaces

Then the following commands to deploy it Docker locally:

npm run java:docker:arm64
cd docker-compose
docker stop $(docker ps -a -q);
docker compose up -d

And finally, in the gateway folder run npm run start to get the frontend on port 9000. After, just login as admin, and try to create a Tag, and after that a Post, and associate that Post with that Tag on the creation process. After this, both their pages will stop loading correctly.

Related issues
Suggest a Fix
JHipster Version(s)

8.5.0

JHipster configuration
WARNING! Since JHipster v8, the jhipster command will not use the locally installed generator-jhipster.
    If you want to execute the locally installed generator-jhipster, run: npx jhipster

        ██╗ ██╗   ██╗ ████████╗ ███████╗   ██████╗ ████████╗ ████████╗ ███████╗
        ██║ ██║   ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗
        ██║ ████████║    ██║    ███████╔╝ ╚█████╗     ██║    ██████╗   ███████╔╝
  ██╗   ██║ ██╔═══██║    ██║    ██╔════╝   ╚═══██╗    ██║    ██╔═══╝   ██╔══██║
  ╚██████╔╝ ██║   ██║ ████████╗ ██║       ██████╔╝    ██║    ████████╗ ██║  ╚██╗
   ╚═════╝  ╚═╝   ╚═╝ ╚═══════╝ ╚═╝       ╚═════╝     ╚═╝    ╚═══════╝ ╚═╝   ╚═╝
                            https://www.jhipster.tech
Welcome to JHipster v8.5.0

Welcome to the JHipster Information Sub-Generator
microservices-test@ /Users/user/Documents/IdeaProjects/microservices-test
├─┬ blog@0.0.1-SNAPSHOT -> ./blog
│ └── generator-jhipster@8.5.0
├─┬ gateway@0.0.1-SNAPSHOT -> ./gateway
│ └── generator-jhipster@8.5.0 deduped
└─┬ store@0.0.1-SNAPSHOT -> ./store
  └── generator-jhipster@8.5.0 deduped
JHipster configuration, a .yo-rc.json file generated in the root folder
.yo-rc.json file
{
  "generator-jhipster": {
    "appsFolders": [
      "gateway",
      "blog",
      "store"
    ],
    "baseName": "workspaces",
    "clientPackageManager": "npm",
    "directoryPath": "./",
    "dockerCompose": true,
    "jhipsterVersion": "8.5.0",
    "monorepository": true
  }
}
.yo-rc.json file for gateway
{
  "generator-jhipster": {
    "applicationIndex": 0,
    "applicationType": "gateway",
    "applications": {
      "blog": {
        "applicationIndex": 1,
        "clientFramework": "angular",
        "serverPort": "8081"
      },
      "store": {
        "applicationIndex": 2,
        "clientFramework": "angular",
        "serverPort": "8082"
      }
    },
    "authenticationType": "oauth2",
    "baseName": "gateway",
    "buildTool": "maven",
    "clientFramework": "angular",
    "devServerPort": 4200,
    "entities": [],
    "jhipsterVersion": "8.5.0",
    "languages": [
      "en"
    ],
    "microfrontends": [
      {
        "baseName": "blog"
      },
      {
        "baseName": "store"
      }
    ],
    "monorepository": true,
    "nativeLanguage": "en",
    "packageFolder": "com/okta/developer/gateway",
    "packageName": "com.okta.developer.gateway",
    "prodDatabaseType": "postgresql",
    "reactive": true,
    "serverPort": 8080,
    "serviceDiscoveryType": "consul",
    "skipCommitHook": true,
    "skipUserManagement": true,
    "testFrameworks": [
      "cypress"
    ]
  }
}
.yo-rc.json file for blog
{
  "generator-jhipster": {
    "applicationIndex": 1,
    "applicationType": "microservice",
    "authenticationType": "oauth2",
    "baseName": "blog",
    "buildTool": "maven",
    "clientFramework": "angular",
    "databaseType": "neo4j",
    "devDatabaseType": "neo4j",
    "devServerPort": 4201,
    "enableHibernateCache": false,
    "entities": [
      "Blog",
      "Post",
      "Tag"
    ],
    "jhipsterVersion": "8.5.0",
    "languages": [
      "en"
    ],
    "lastLiquibaseTimestamp": 1717768722000,
    "monorepository": true,
    "nativeLanguage": "en",
    "packageFolder": "com/okta/developer/blog",
    "packageName": "com.okta.developer.blog",
    "prodDatabaseType": "neo4j",
    "reactive": true,
    "serverPort": "8081",
    "serviceDiscoveryType": "consul",
    "skipCommitHook": true,
    "skipUserManagement": true,
    "testFrameworks": [
      "cypress"
    ]
  }
}
.yo-rc.json file for store
{
  "generator-jhipster": {
    "applicationIndex": 2,
    "applicationType": "microservice",
    "authenticationType": "oauth2",
    "baseName": "store",
    "buildTool": "maven",
    "clientFramework": "angular",
    "databaseType": "mongodb",
    "devDatabaseType": "mongodb",
    "devServerPort": 4202,
    "enableHibernateCache": false,
    "entities": [
      "Product"
    ],
    "jhipsterVersion": "8.5.0",
    "languages": [
      "en"
    ],
    "lastLiquibaseTimestamp": 1717768602000,
    "monorepository": true,
    "nativeLanguage": "en",
    "packageFolder": "com/okta/developer/store",
    "packageName": "com.okta.developer.store",
    "prodDatabaseType": "mongodb",
    "reactive": true,
    "serverPort": "8082",
    "serviceDiscoveryType": "consul",
    "skipCommitHook": true,
    "skipUserManagement": true,
    "testFrameworks": [
      "cypress"
    ]
  }
}
Environment and Tools

openjdk version "17.0.10" 2024-01-16 LTS OpenJDK Runtime Environment Corretto-17.0.10.7.1 (build 17.0.10+7-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.10.7.1 (build 17.0.10+7-LTS, mixed mode, sharing)

git version 2.39.3 (Apple Git-146)

node: v20.14.0 npm: 10.7.0

Docker version 26.1.1, build 4cf5afa

JDL for the Entity configuration(s) entityName.json files generated in the .jhipster directory
JDL entity definitions

Congratulations, JHipster execution is complete! If you find JHipster useful consider sponsoring the project https://www.jhipster.tech/sponsors/

Thanks for using JHipster!

JDL definitions
   application {
        config {
          baseName gateway
          reactive true
          packageName com.okta.developer.gateway
          applicationType gateway
          authenticationType oauth2
          buildTool maven
          clientFramework angular
          prodDatabaseType postgresql
          serviceDiscoveryType consul
          testFrameworks [cypress]
          microfrontends [blog, store]
        }
      }

      application {
        config {
          baseName blog
          reactive true
          packageName com.okta.developer.blog
          applicationType microservice
          authenticationType oauth2
          buildTool maven
          clientFramework angular
          databaseType neo4j
          devDatabaseType neo4j
          prodDatabaseType neo4j
          enableHibernateCache false
          serverPort 8081
          serviceDiscoveryType consul
          testFrameworks [cypress]
        }
        entities Blog, Post, Tag
      }

      application {
        config {
          baseName store
          reactive true
          packageName com.okta.developer.store
          applicationType microservice
          authenticationType oauth2
          buildTool maven
          clientFramework angular
          databaseType mongodb
          devDatabaseType mongodb
          prodDatabaseType mongodb
          enableHibernateCache false
          serverPort 8082
          serviceDiscoveryType consul
          testFrameworks [cypress]
        }
        entities Product
      }

      entity Blog {
        name String required minlength(3)
        handle String required minlength(2)
      }

      entity Post {
        title String required
        content TextBlob required
        date Instant required
      }

      entity Tag {
        name String required minlength(2)
      }

      entity Product {
        title String required
        price BigDecimal required min(0)
        image ImageBlob
      }

      relationship ManyToOne {
        Blog{user(login)} to User with builtInEntity
        Post{blog(name)} to Blog
      }

      relationship ManyToMany {
        Post{tag(name)} to Tag{post}
      }

      paginate Post, Tag with infinite-scroll
      paginate Product with pagination

      deployment {
        deploymentType docker-compose
        serviceDiscoveryType consul
        appsFolders [gateway, blog, store]
        dockerRepositoryName "mraible"
      }
Entity configuration(s) entityName.json files generated in the .jhipster directory

Post.json

{
  "annotations": {
    "changelogDate": "20240607135742"
  },
  "applications": ["blog"],
  "clientRootFolder": "blog",
  "databaseType": "neo4j",
  "fields": [
    {
      "fieldName": "title",
      "fieldType": "String",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "content",
      "fieldType": "byte[]",
      "fieldTypeBlobContent": "text",
      "fieldValidateRules": ["required"]
    },
    {
      "fieldName": "date",
      "fieldType": "Instant",
      "fieldValidateRules": ["required"]
    }
  ],
  "microserviceName": "blog",
  "name": "Post",
  "pagination": "infinite-scroll",
  "relationships": [
    {
      "otherEntityField": "name",
      "otherEntityName": "blog",
      "relationshipName": "blog",
      "relationshipSide": "left",
      "relationshipType": "many-to-one"
    },
    {
      "otherEntityField": "name",
      "otherEntityName": "tag",
      "otherEntityRelationshipName": "post",
      "relationshipName": "tag",
      "relationshipSide": "left",
      "relationshipType": "many-to-many"
    }
  ],
  "searchEngine": "no"
}

Tag.json

{
  "annotations": {
    "changelogDate": "20240607135842"
  },
  "applications": ["blog"],
  "clientRootFolder": "blog",
  "databaseType": "neo4j",
  "fields": [
    {
      "fieldName": "name",
      "fieldType": "String",
      "fieldValidateRules": ["required", "minlength"],
      "fieldValidateRulesMinlength": "2"
    }
  ],
  "microserviceName": "blog",
  "name": "Tag",
  "pagination": "infinite-scroll",
  "relationships": [
    {
      "otherEntityName": "post",
      "otherEntityRelationshipName": "tag",
      "relationshipName": "post",
      "relationshipSide": "right",
      "relationshipType": "many-to-many"
    }
  ],
  "searchEngine": "no"
}
Browsers and Operating System

Mac OS X 14.5, tested in Microsoft Edge.

github-actions[bot] commented 3 months ago

JHipster has completed the sample check .yo-rc.json: valid Entities JDL: blank Application: successfully generated Frontend check: skipped Backend check: skipped E2E check: skipped

This check uses jhipster info output from the issue description to generate the sample. Bug report that does not contain this information will be marked as invalid.