speedment / jpa-streamer

JPAstreamer is a lightweight library for expressing JPA queries as Java Streams
GNU Lesser General Public License v2.1
345 stars 35 forks source link

"Films$" class nowhere to be found in your sample code #234

Closed martinfr87 closed 2 years ago

martinfr87 commented 2 years ago

Sample code for JPA Streamer can be found here:

https://github.com/speedment/jpa-streamer-demo/blob/master/hibernate/src/main/java/com/speedment/jpastreamer/demo/hibernate/SimpleDemo1WithJoining.java

Excerpt:

import com.speedment.jpastreamer.demo.hibernate.model.Film;
import com.speedment.jpastreamer.demo.hibernate.model.Film$;
[...]
        jpaStreamer.stream(of(Film.class).joining(Film$.actors).joining(Film$.language))
            .filter(Film$.length.between(100, 120, START_INCLUSIVE_END_EXCLUSIVE))
            .forEach(System.out::println);

The Film class of the model is located here:

https://github.com/speedment/jpa-streamer-demo/tree/master/hibernate/src/main/java/com/speedment/jpastreamer/demo/hibernate/model/Film.java

But where is the "Films$" class? Without this class, the sample code is useless. How can this class be generated? Your documentation uses 'Table$' model classes everywhere:

https://github.com/speedment/jpa-streamer/blob/master/docs/modules/fetching-data/pages/sql-equivalents.adoc

jpaStreamer.stream(Film.class)
    .filter(Film$.length.greaterThan(120))
    .forEachOrdered(System.out::println);

https://speedment.github.io/jpa-streamer/jpa-streamer/0.1.7/fetching-data/stream-examples.html

import static com.speedment.jpastreamer.streamconfiguration.StreamConfiguration.*;
...
jpaStreamer.stream(of(Film.class).joining(Film$.actors).joining(Film$.language))
    .filter(Film$.length.between(100, 120))
    .forEach(System.out::println);

I have been using JPA with H2 databases so far, through Hibernate 5.5, and Hibernate generates two tables, "Film", and "Film_". This latter class holds columns. I don't see any "Film$" class anywhere. What am I missing?

minborg commented 2 years ago

The Film$ class is generated dynamically by an annotation processor. Usually, it ends up in the "target/generated-sources" directory. Generation is made when you compile the project.

martinfr87 commented 2 years ago

Thanks for your reply. I am using H2, not MySQL and the Hibernate JPA-compliant entity generation process does not create "Table$" classes for my H2 database. I suspect Table$ class generation is specific to MySQL. Will JPA Streamer work in this case? How can I carry out joins?

minborg commented 2 years ago

The generation of classes is totally independent on which database is used. Are you using Maven or Gradle as your build tool?

martinfr87 commented 2 years ago

I currently explictly generate entity classes from Eclipse, using the JPA Tools. The JPA Tools look at META-INF/persistence.xml and generate the classes using the jdbc:h2: connection string. Maybe this generation is not as good as the one provided by Maven. My Eclipse project itself is a Maven project, but I haven't found a way to streamline JPA class generation inside the pom.xml. How can I have Maven look at META-INF/persistence.xml and generate code (so that I don't have to do it myself in Eclipse)?

minborg commented 2 years ago

You can't. You need the entity classes and the meta classes will be generated from them.

martinfr87 commented 2 years ago

I know. Meta classes are automatically generated by Eclipse from the entity classes when I set an option in the project settings. Maven neither automatically generates entity classes from the database, nor does it automatically generate meta classes from entity classes.

With Eclipse, generated meta class names are in the form 'Table', not 'Table$'. 'Table' classes are used in eg. CriteriaQuery queries.

Here is an example of a meta class generated by Eclipse:

import javax.annotation.Generated;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@Generated(value="Dali", date="2022-03-12T09:49:04.922+0100")
@StaticMetamodel(Customers.class)
public class Customers_ {
    public static volatile SingularAttribute<Customers, Integer> id;
    public static volatile SingularAttribute<Customers, String> company;
    public static volatile SingularAttribute<Customers, String> lastName;
    [...]

JPAStreamer expects 'Table$'. Can JPA Streamer 'joining' method work with such a meta class?

minborg commented 2 years ago

Table_ and Table$ are two different things.

Try using only Maven and not Eclipse-specific features.

Are you able to run the demos in the JPAstremer demo project?

martinfr87 commented 2 years ago

I have

and the result I get is that Table$ classes are nowhere to be found. I get a compilation error in, eg., com.speedment.jpastreamer.demo.hibernate.SimpleDemo1.java. The following line of code:

import com.speedment.jpastreamer.demo.hibernate.model.Film$;

returns an error:

The import com.speedment.jpastreamer.demo.hibernate.model.Film$ cannot be resolved.

'Film' can be resolved, as it is provided in your source tree. But not 'Film$'. If this class should normally be generated by the Maven build process, well, it isn't.

martinfr87 commented 2 years ago

I just tried to compile from the command line, and it works. It does find a Film$ class. What the heck is wrong in Eclipse? What is the line (or the lines) in the pom.xml file that specifically asks Maven to generate Table$ classes from annotations? I can't develop from the command line. I need to import the project into Eclipse, without that I won't be able to move forward in my testing, playing and experimentations with JPA Streamer.

martinfr87 commented 2 years ago

The problem definitely comes from Eclipse. I did a Maven -> 'Update project' to be sure to be on the safe side and nope, the project files do get compiled into target/classes, but target/generated-sources does not get generated.

I see that you have the following comment in your pom.xml (first line below):

            <!-- Needed by some IDEs -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>
                                    ${project.build.directory}/generated-sources/annotations
                                </source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Maybe Eclipse ignores all of this? Any idea about how I can fix that?

minborg commented 2 years ago

I was just about to suggest adding the plugin you just mentioned.

Most developers use IntelliJ these days. That works rock solid. Are you open to trying it?

martinfr87 commented 2 years ago

Will this work in Visual Studio Code?

martinfr87 commented 2 years ago

It does not work in Visual Studio Code, I just checked: VS Code does not generate files in 'generated-sources'. If I pregenerate files from the command line, the project runs fine from VS code but the editor does not see the 'Film$' class (running or debugging the project will be fine, but the editor has no knowledge there is source code in 'generated-sources' and hints for a compilation error in the editor window).

Visual Studio Code is vastly popular nowadays, even for Java code. I am no specialist, but I think there must be a problem with the way you declared things in pom.xml, to be honest. I can't switch to IntelliJ unfortunately.

minborg commented 2 years ago

It is sad that the tools you are using do not support Maven fully, but it is not much we can do about that. If you can build using the Maven command tool, then JPAstreamer works as it should.

martinfr87 commented 2 years ago

I am fairly sure this is easy enough to fix.

I was just about to suggest adding the plugin you just mentioned.

build-helper-maven-plugin only registers additional source code folders for the subsequent compile phase. It does not generate Table$ classes from Entity classes.

What, in the pom.xml file, says annotations should be looked at and processed as part of the Maven build?

minborg commented 2 years ago

Some tools require that you manually enable "annotation processors". Can you check that that's enabled in the IDEs you are using, please?

martinfr87 commented 2 years ago

I went ahead and decided to install IntelliJ. When I import the project, still, Table$ classes are not found.

I get:

Cannot resolve symbol 'Actor$'

Here's what I did:

I am still getting the 'Actor$' error. Things do not get generated in the 'generated-source/annotations' folder. They only do when I run mvn from the command line.

minborg commented 2 years ago

Please make sure you tick in "Enable annotation processing" . In the picture below, it is NOT ticked in and that might cause the problem you have.

image
martinfr87 commented 2 years ago

It wasn't ticked, thanks. Even when ticked, loading the project does not automatically generate the annotations. Building the project does not either. The only thing which triggers the generation process is to actually run eg. SimpleDemo1, or to manually issue a mvn install from IntelliJ. Does this sound normal to you?

minborg commented 2 years ago

I've never seen this or heard about it before so no, it does not sound normal.

martinfr87 commented 2 years ago

I can live with a manual mvn install every time the database changes. I double checked and started from scratch again but no luck. I am starting my experiments, I have looked at your documentation which is nice, but more examples would be welcome. One last question - is it possible to automate the generation of the Entity classes themselves? eg., through some plugin in the Maven build? Thanks in advance for any information about this, and I should be ready to go.

minborg commented 2 years ago

JPAstreamer cannot generate entity classes but I know there are a bunch of other tools that can. Good luck with your tests and let me know the outcome!