Skip to content

HQL console in DevUI is not working #47663

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

Closed
omasseau opened this issue May 2, 2025 · 12 comments · Fixed by #47979
Closed

HQL console in DevUI is not working #47663

omasseau opened this issue May 2, 2025 · 12 comments · Fixed by #47979
Assignees
Labels
area/dev-ui area/hibernate-orm Hibernate ORM kind/bug Something isn't working
Milestone

Comments

@omasseau
Copy link

omasseau commented May 2, 2025

Describe the bug

See: #46728

The DevUI HQL console is not working in latest version of quarkus (3.22.1)

It just display this error :
Error executing query: Unable to encode results as JSON. Note circular associations are not supported at the moment, use @JsonIgnore to break circles.

Expected behavior

HQL Console should work with such a basic entity :

@Entity
public class MyEntity extends PanacheEntity {
    public String field;
}

Actual behavior

HQL Console displays an error.
The error message is misleading (there are no cicular associations here).

How to Reproduce?

To reproduce the problem:

  • Go to https://code.quarkus.io/
  • Generate a new project using the 'REST service with database' preset
  • Add this in import.sql :
    insert into myentity (id, field) values(1, 'field-1');
  • Start the app and go the the HQL console -> You will see the error displayed :

Image

Output of uname -a or ver

No response

Output of java -version

21.0.3

Quarkus version or git rev

3.22.1

Build tool (ie. output of mvnw --version or gradlew --version)

maven 3.9.9

Additional information

No response

@omasseau omasseau added the kind/bug Something isn't working label May 2, 2025
Copy link

quarkus-bot bot commented May 2, 2025

/cc @cescoffier (devui), @phillip-kruger (devui)

@phillip-kruger
Copy link
Member

@mbladel ^^^

@maxandersen
Copy link
Member

i didn't see the hql console - but are we really serializing the object graph to the ui here? that seems not necessary as on client side we would just do tostring anyway wouldnt we?

@yrodiere
Copy link
Member

yrodiere commented May 5, 2025

but are we really serializing the object graph to the ui here?

That's a temporary implementation which -- as explained in the error message -- is very limited.
We need proper support for turning entities to strings in Hibernate ORM in order to do better, and @mbladel is working on that.

we would just do tostring anyway wouldnt we?

This does seem like a much simpler temporary solution indeed, but quite limiting (people don't always implement toString(), and Panache's impl gives very little info...).


The fact remains that the error reported in this issue doesn't seem normal at all. I would guess the implementation depends on the presence of Jackson, which is absent in the reproducer? Something like that?

@mbladel
Copy link
Member

mbladel commented May 5, 2025

Thanks @omasseau for reporting the issue and providing the steps to reproduce it. I've debugged the error, and it seems like it's caused by the PanacheEntityBase#isPersistent() method being invoked during serialization, which fails to acquire a new session and errors out.

The method is marked as @JsonIgnore, though, so this shouldn't be happening:

@JsonIgnore
public boolean isPersistent() {
return JpaOperations.INSTANCE.isPersistent(this);
}

Diving a bit deeper into the error, it looks like the ObjectMapper we're using tries to look for a different instance of the com.fasterxml.jackson.annotation.JsonIgnore class than the one that is stored in the com.fasterxml.jackson.databind.introspect.AnnotatedMethod for PanacheEntityBase#isPersistent(). Looking into the class loaders for these, we see:

  • Augmentation Class Loader: DEV for code-with-quarkus-1.0.0-SNAPSHOT for the class the current ObjectMapper is looking for
  • Quarkus Base Runtime ClassLoader: DEV for code-with-quarkus-1.0.0-SNAPSHOT for the one stored in the AnnotatedMethod instance

Since the internal implementation uses a HashMap, it's as if the @JsonIgnore annotation was not present so the serialization of that field is triggered.

Reminder that the ObjectMapper we use is the same as the one that does all the Dev-UI default marshaling for methods returning objects, which should be using https://github.com/quarkusio/quarkus/blob/main/extensions/vertx-http/deployment/src/main/java/io/quarkus/devui/deployment/jsonrpc/DevUIDatabindCodec.java, and from the stack trace that's the first class which has the Augmentation Class Loader instead of the runtime one. @phillip-kruger any idea on a possible fix?


that seems not necessary as on client side we would just do tostring anyway wouldnt we

@maxandersen we need a JSON-representation of the object tree returned by the query, to present results in a formatted table. We are manually invoking serialization (instead of relying on the default JSON marshaling) because managed entities might have lazy fields and / or circular associations which need special handling. For now circularity is not prevented, as we're waiting for the feature to be included on the Hibernate side and released, so we are producing a special error message.

@phillip-kruger
Copy link
Member

We can't guarantee that Jackson is available on the runtime class path, that is why we always use the one from deployment. You can always go object to map in your jsonrpc service. That should then ignore the field, once it gets to dev ui it will go map to json

@melloware
Copy link
Contributor

+1 just hit this error myself.

@yrodiere yrodiere added the area/hibernate-orm Hibernate ORM label May 12, 2025
@mbladel
Copy link
Member

mbladel commented May 12, 2025

You can always go object to map in your jsonrpc service. That should then ignore the field

@phillip-kruger Not sure what you mean by this: are you saying I should create a Map<String, String> for each field in the resulting object? I'm not sure how I would go about doing that, as the result of an HQL query could be of any type (an Entity instance, an Embeddable, a single basic-typed value) so I cannot extract single values. That's why I'm relying on Jackson's serialization in the first place.

@yrodiere
Copy link
Member

You can always go object to map in your jsonrpc service. That should then ignore the field

@phillip-kruger Not sure what you mean by this: are you saying I should create a Map<String, String> for each field in the resulting object? I'm not sure how I would go about doing that, as the result of an HQL query could be of any type (an Entity instance, an Embeddable, a single basic-typed value) so I cannot extract single values. That's why I'm relying on Jackson's serialization in the first place.

Yes, we're dealing with arbitrary data here, I don't think this would work.

I'd say we have three options:

  1. Find some way of configuring the dev UI's ObjectMapper to ignoring fields annotated with @JsonIgnore, even if that @JsonIgnore is from another classloader. I imagine there are options to have custom "ignore strategies" in Jackson, so we could have one that looks at the class name of all annotations for a given field.
  2. Use the better solution you've already been working on. Either by merging it into Hibernate ORM, or, if not possible, by copy-pasting the code while we're waiting for it being integrated in Hibernate ORM.

Looks like either 1 or 2 (copy-pasting alternative) could be implemented in a realistic time frame, as a quick fix?

@phillip-kruger
Copy link
Member

I meant using Jackson to go from Object to Map (rather than json)

@phillip-kruger
Copy link
Member

So at the moment you create an object that you return in your JsonRPC Service (right ?). On the way back to the browser that object gets to the Dev UI JsonRPC Router and there we use Jackson to create json to send to the browser. That Jackson is not the one you want (right ?)

I am saying, creating a Map from the object in your JsonRPC service using your Jackson should solve the issue. Then the map will get to the JsonRPC Router and go to json.

@mbladel
Copy link
Member

mbladel commented May 13, 2025

@yrodiere thanks for the suggestions. Regarding 2., merging it into ORM is not really an easy option as we're waiting for the final release of 7 (which will take some time before being available in Quarkus I'm guessing), and the new features would probably land in 7.1. Let's see what we can do, and at worst fall back to 1. for the moment.


@phillip-kruger no, we are not returning an object and using the default serialization. We are actually manually invoking serialization on the query results here:

We don't know the structure of the arbitrary objects we're serializing so I don't know how we would create a map from them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/dev-ui area/hibernate-orm Hibernate ORM kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants