hilla icon indicating copy to clipboard operation
hilla copied to clipboard

hilla - autocrud: entities with mapped superclass not supported?

Open fer-marino opened this issue 8 months ago • 8 comments

Describe the bug

Hi, I've noticed that if the entity I'm creating the autocrud component from is extending a mapped superclass, the generated UI components includes only the properties of the superclass, not the entity itself. Is this a bug or am I doing something wrong?

thanks

Expected-behavior

all mapped properties are used

Reproduction

create a jpa mapped super class and an entity that extends it. Then create an autocrud component for the entity.

System Info

gradle, spring boot, hilla. All latest

fer-marino avatar Mar 18 '25 13:03 fer-marino

Hi @fer-marino,

I'm not sure if I'm able to reproduce this issue. There are integration tests in the Hilla repository that shows this works:

  • Maven with Java entities: https://github.com/vaadin/hilla/tree/main/packages/java/tests/spring/react-grid-test

  • Gradle with Kotlin entities: https://github.com/vaadin/hilla/tree/main/packages/java/tests/gradle/kotlin-gradle-test

If you have a case that doesn't work, please consider including a reproducible example.

taefi avatar Mar 25 '25 13:03 taefi

Hi @fer-marino, could you send or describe how the crud service definition in Java looks like in your case? I'm asking because the Hilla parser would take the entity type argument from there.

platosha avatar Mar 27 '25 12:03 platosha

I Will wrap up a sample project, just give me some time please

On Thu, Mar 27, 2025, 13:16 Anton Platonov @.***> wrote:

Hi @fer-marino https://github.com/fer-marino, could you send or describe how the crud service definition in Java looks like in your case? I'm asking because the Hilla parser would take the entity type argument from there.

— Reply to this email directly, view it on GitHub https://github.com/vaadin/hilla/issues/3361#issuecomment-2757830772, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOIYA6EOOTAHMX3YEG7UH32WPMYDAVCNFSM6AAAAABZIHP2ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONJXHAZTANZXGI . You are receiving this because you were mentioned.Message ID: @.***> [image: platosha]platosha left a comment (vaadin/hilla#3361) https://github.com/vaadin/hilla/issues/3361#issuecomment-2757830772

Hi @fer-marino https://github.com/fer-marino, could you send or describe how the crud service definition in Java looks like in your case? I'm asking because the Hilla parser would take the entity type argument from there.

— Reply to this email directly, view it on GitHub https://github.com/vaadin/hilla/issues/3361#issuecomment-2757830772, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOIYA6EOOTAHMX3YEG7UH32WPMYDAVCNFSM6AAAAABZIHP2ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONJXHAZTANZXGI . You are receiving this because you were mentioned.Message ID: @.***>

fer-marino avatar Mar 27 '25 20:03 fer-marino

I've investigated the issue a bit more. My endpoint returns a generic T extends Superclass which might be an instance of any mapped class inheriting from it. Vaadin generates the corresponding typescript class only for the superclass, instead of the whole hierarchy. It is worth noting that in my endpoints there is no mention of the child classes elsewhere.

All classes are mapped entity with jpa and spring data. There is only one repository related to the superclass so no mention to child classes even there

fer-marino avatar Apr 02 '25 11:04 fer-marino

I think it will be very helpful if you could provide a minimal project or at least some code snippet with the exact method signatures for the endpoint and the entities that reproduces your issue, otherwise we have to guess between the cases that are not supported and/or a misconfiguration.

For example, something like this:

@BrowserCallable
public class GenericCrudService {

  public <T> T save(T value) {
    // save using repository
    return value;
  }
}

will generate:

async function save_1(value: unknown, init?: EndpointRequestInit_1): Promise<unknown> { 
  return client_1.call("GenericCrudService", "save", { value }, init); 
}

or something like this:

@BrowserCallable
public class GenericCrudService {

  public <ID, T extends AbstractEntity<ID>> T save(T value) {
    // save using repository
    return value;
  }
}

will generate:

async function save_1(value: AbstractEntity_1<unknown>, init?: EndpointRequestInit_1): Promise<AbstractEntity_1<unknown>> {
  return client_1.call("GenericCrudService", "save", { value }, init); 
}

or something like this:

@BrowserCallable
public class GenericCrudService<ID, T extends AbstractEntity<ID>> {

  public T save(T value) {
    // save using repository
    return value;
  }
}

will generate:

async function save_1(value: AbstractEntity_1<unknown>, init?: EndpointRequestInit_1): Promise<AbstractEntity_1<unknown>> {
  return client_1.call("GenericCrudService", "save", { value }, init); 
}

From the above examples, you can see the generator behavior is based on the AbstractEntity as the upper bound, since at generation phase, it is not possible to find out what could be the dynamic type of the T that extends the AbstractEntity, and if you happen to have a generic CRUD service that extends the CrudRepositoryService, of course, only the properties of the AbstractEntity are populated in the UI, though, still not sure what your service looks like, and these are just speculations.

taefi avatar Apr 02 '25 15:04 taefi

My endpoint returns a generic T extends Superclass which might be an instance of any mapped class inheriting from it. Vaadin generates the corresponding typescript class only for the superclass, instead of the whole hierarchy. It is worth noting that in my endpoints there is no mention of the child classes elsewhere.

Since autocrud relies on static code analysis, it is not reasonable to find out which subclasses to use. It looks like using Superclass boundary is the best we could do in this case at the moment.

I would suggest to have an endpoint subclass using concrete entity classes for this case.

platosha avatar Apr 09 '25 11:04 platosha

thanks @platosha . I thought vaadin was doing some magic using jpa annotations to infer all mapped entity and this was somehow broken. As you suggested anyway, I've added some dummy endpoint with the child classes and now the corresponding typescript code is generated.

fer-marino avatar Apr 09 '25 13:04 fer-marino

Some further considerations about code generation are in https://github.com/vaadin/hilla/issues/3394.

cromoteca avatar Apr 09 '25 14:04 cromoteca