eclipse / jnosql

Eclipse JNoSQL is a framework which has the goal to help Java developers to create Jakarta EE applications with NoSQL.
Other
229 stars 72 forks source link

[BUG] Problem with Inheritance with enum field #508

Closed m4ttek closed 3 months ago

m4ttek commented 4 months ago

Which JNoSQL project the issue refers to?

JNoSQL (Core)

Bug description

It seems there is a bug with inheritance functionality which causes weird behaviour when using enum field as discriminator field.

Caused by: jakarta.data.exceptions.MappingException: There is no inheritance map to the discriminator column value TEXT_OPINION
    at org.eclipse.jnosql.mapping.semistructured.EntityConverter.lambda$mapInheritanceEntity$12(EntityConverter.java:228)
    at java.base/java.util.Optional.orElseThrow(Unknown Source)
    at org.eclipse.jnosql.mapping.semistructured.EntityConverter.mapInheritanceEntity(EntityConverter.java:228)
    at org.eclipse.jnosql.mapping.semistructured.EntityConverter.toEntity(EntityConverter.java:134)
    at org.eclipse.jnosql.mapping.semistructured.DefaultEntityConverter$Proxy$_$$_WeldClientProxy.toEntity(Unknown Source)
    at org.eclipse.jnosql.mapping.semistructured.AbstractSemiStructuredTemplate.lambda$executeQuery$7(AbstractSemiStructuredTemplate.java:266)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)

This implementation in EntityConverter doesn't take into consideration other types of fields, only strings:

String discriminator = entity.find(column, String.class)

JNoSQL Version

1.1.0

Steps To Reproduce

This case is quite difficult to reproduce, because I wasn't able to catch it in my integration tests. It looks like there is needed context switching etc.

Expected Results

I should be able to use enum fields as discriminator fields

Code example, screenshot, or link to a repository

The base class for inheritance looks like this:

@SuperBuilder
@Entity(COLLECTION_NAME)
@Inheritance
@DiscriminatorColumn("componentType")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public sealed abstract class ComponentConfiguration permits
        TextOpinionComponentConfiguration,
        UtilComponentConfiguration {

    public static final String COLLECTION_NAME = "component_configurations";

    @InternalId
    @Id
    private String id;
    @InternalKey
    @Column("_key")
    private String key;

    @Column
    @NotNull
    private ComponentType componentType;
}
otaviojava commented 4 months ago

hey @m4ttek

Thanks for reporting this issue.

We never tried this combination, but it makes sense.

I am working to fix it ASAP.

otaviojava commented 4 months ago

@m4ttek Is there any class with the @DiscriminatorValuewith the value TEXT_OPINION?

I tested with this sample code and worked:

@Entity
@Inheritance
@DiscriminatorColumn("type")
public abstract class Transport {

    @Id
    protected String id;
    @Column
    protected String name;
    @Column
    protected TransportType type;
}

public enum TransportType {
    BOAT, CAR, PLANE;
}

@Entity
@DiscriminatorValue("CAR")
public class Car extends Transport {

    public Car() {
        this.type = TransportType.CAR;
    }
}
m4ttek commented 4 months ago

@otaviojava yep, it works in simple test, but when deployed on a real test environment it starts to behave nondeterministic. Unfortunately I don't have any specific scenario which causes it to start throwing exceptions. As I wrote, in my integration tests it also works perfectly ;)

Try building simple application with multithreaded contexts using jakarta data repositories. In my case, I'm using Helidon 4 for REST services.

What is interesting, rewriting my code to use standard denominator column (dtype) resulted in everything working without any trouble.

m4ttek commented 4 months ago

@otaviojava I was mistaken with the standard denominator column. Similarly, the problem started to occur with the standard string field. Database records contain proper field: image

but there is an exception thrown:

Caused by: jakarta.data.exceptions.MappingException: There is no inheritance map to the discriminator column value TEXT_OPINION
    at org.eclipse.jnosql.mapping.semistructured.EntityConverter.lambda$mapInheritanceEntity$12(EntityConverter.java:228)
    at java.base/java.util.Optional.orElseThrow(Unknown Source)
    at org.eclipse.jnosql.mapping.semistructured.EntityConverter.mapInheritanceEntity(EntityConverter.java:22

It shows up after application works for a longer period. Maybe it somehow depends on multithreading contexts...

Additionally, I checked what is happening inside mapInheritanceEntity: image In reality I have more entity classes that are not present here: image

I don't know why there is only a part of these classes

m4ttek commented 4 months ago

I think this code is not safe in multithreaded environment, it should use computeIfAbsent method which is thread safe in concurrent hash map implementation: image

m4ttek commented 4 months ago

Yep, I've created an alternative bean with a fix and it seems to be working right now. I can provide a pull request with this change if you wish.

dearrudam commented 4 months ago

Hi, @m4ttek! I'm working on this issue, but please feel free to provide a PR with this change, okay?!

m4ttek commented 4 months ago

@dearrudam I've provided fix for this issue, I hope it helps, tomorrow we'll be sure in our project if it is enough

otaviojava commented 4 months ago

@m4ttek, we can release a new version of this fix next week.

Again, thank you for the help.

m4ttek commented 4 months ago

@otaviojava I'm using alternative bean with this fix in my project, and I haven't seen any new problem since introducing it. So, it should be fine now