This is the further question to this:
How to use JPA Criteria API in JOIN
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Company> criteria = criteriaBuilder.createQuery( Company.class );
Root<Company> companyRoot = criteria.from( Company.class );
Join<Company,Product> products = companyRoot.join("dentist");
Join<Company, City> cityJoin = companyRoot.join("address.city");//Company->Address->City-city
criteria.where(criteriaBuilder.equal(products.get("category"), "dentist"), criteriaBuilder.equal(cityJoin.get("city"),"Leeds"));
A company has an address, inside the address there is City-pojo and Country-Pojo. How can I use it in JOIN? I tried to reference it with address.city but I got the error message:
The attribute [address.city] from the managed type
[EntityTypeImpl#1692700229:Company [ javaType: class
com.test.domain.Company descriptor:
RelationalDescriptor(com.test.domain.Company -->
[DatabaseTable(COMPANY)]), mappings: 16]] is not present.
If you use canonical Metamodel, you'll avoid this kind of errors.
In your code you have misused the "dentist" keyword, that's probably the cause of your error, because "dentist" is not a field in Company entity.
However, looking at how you defined your class in the other question, the way to define that join using Metamodel is this:
SetJoin<Company,Product> products = companyRoot.join(Company_.products);
As you can see, Metamodel avoids the use of strings, and so avoids a lot of runtime errors. If anyway you don't use Metamodel, try this:
SetJoin<Company,Product> products = companyRoot.join("products");
If you now want to add a predicate, i.e. something after the where, you'll write something like:
Predicate predicate = criteriaBuilder.equal(products.get(Product_.category), "dentist");
criteria.where(predicate);
If you want to add a join for the City entity:
Join<Company, City> city = companyRoot.join(Company_.city);
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(city.get(City_.cityName), "Leeds");
criteria.where(predicate);
(supposing that the field cityName is the correct field name for your city).
Agree with #perissf.
I can't comment but the symbol "Company_" is the metadata class file which contains all the attribute name of the model class.
I strongly suggest to use metadata classes, you can autogenerate metadata classes using the maven processor plugin using org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor as processor in your configuration.
This example pom plugin xml should work it out :
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${version.hibernate-jpamodelgen}</version>
</dependency>
</dependencies>
</plugin>
Related
In Spring Data JPA, when I want to write a custom query, if I specify a parameter, I send this parameter value with #Param annotation, Is it possible to get rid of #Param Annotation in Spring Data JPA Repository?
Example Query:
#Query("select u from User where u.name = :name")
User findUserByName(#Param("name") String name);
Desired Query:
#Query("select u from User where u.name = :name")
User findUserByName(String name);
Note, I don't want to use ?0 or something like that I want to use directly name parameters.
Yes, this is perfectly possible. As the Reference describes:
As of version 4, Spring fully supports Java 8’s parameter name discovery based on the -parameters compiler flag. By using this flag in your build as an alternative to debug information, you can omit the #Param annotation for named parameters.
And Stackoverflow has an example how to do that with Maven (and probably for the build tool of your choice as well):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<fork>true</fork>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
I am using Swagger codegen to create Java models to be used in a Spring REST server, and would like to know how to get Swagger to declare each model as a JPA entity.
I generate the code with the swagger-codegen-maven-plugin as follows:
<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.4.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/openApi/Rack.json</inputSpec>
<language>spring</language>
<groupId>com.me</groupId>
<artifactId>rest-server</artifactId>
<apiPackage>com.me.rest.api</apiPackage>
<modelPackage>com.me.rest.model</modelPackage>
<invokerPackage>com.me.rest.invoker</invokerPackage>
<configOptions>
<sourceFolder>src/gen/java/main</sourceFolder>
<java8>true</java8>
<dateLibrary>java8</dateLibrary>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
As I have it now, this is the abbreviated java code that gets generated:
#Validated
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "...")
public class Rack {
#JsonProperty("id")
private Long id = null;
#JsonProperty("name")
private String name = null;
...
}
How do I get Swagger to add the #Entity and #Id JPA annotations, as follows?
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
#Validated
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "...")
public class Rack {
#Id
#JsonProperty("id")
private Long id = null;
#JsonProperty("name")
private String name = null;
...
}
This way, all I would have to do to get Spring to automatically expose these generated classes as REST APIs, would be to add the following to my pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
Then I could create the JPA repositories with Spring-Data, as follows:
public interface RackRepository extends CrudRepository<Rack, Long> {
}
A PR has recently been merged fixing your issue : https://github.com/OpenAPITools/openapi-generator/pull/11775
You need to upgrade your Maven plugin to use the latest version (currently unreleased, only snapshot is available)
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.0.0-SNAPSHOT</version>
...
</plugin>
The configuration might be slightly different.
Then you need to add x-class-extra-annotation and x-field-extra-annotation in your spec.
For instance for the Pet Clinic:
schemas:
Pet:
type: object
x-class-extra-annotation: "#javax.persistence.Entity"
required:
- id
- name
properties:
id:
type: integer
format: int64
x-field-extra-annotation: "#javax.persistence.Id"
name:
type: string
tag:
type: string
While the right way to solve this surely is an extension of swagger-codegen (probably with the introduction of some kind of include/exclude config), I got away with a fairly simply post-processing of the generated files.
In contrast to the OP I use Gradle instead of Maven and leveraged its extended filtering functionality. For Maven it is probably necessary to run a Groovy-script by way of the Groovy-Maven-Plugin, since Maven only supports placeholder substitution (as does Ant, so using the AntRun-Plugin would also not work).
I used a simple heuristic to only include entities with an id - the logic is as follows:
for all Java-files containing an ID-field
include import statement for javax.persistence.* after the package declaration
add the #Entity-annotation before the class definition
for the ID-field, add the annotations #Id and #GeneratedValue
(based on field names, other annotations - #OneToMany etc. - may be added as well)
Gradle-users may find the following task useful as a start:
task generateJpaAnnotations(type: Copy) {
from "${swaggerSources.<modelName>.code.outputDir}/src/main/java"
into "<output dir>
include '**/*.java'
eachFile {
if (it.file.text.contains("private Long id")) {
filter { line -> line.contains('package') ? "$line\nimport javax.persistence.*;" : line }
filter { line -> line.contains('public class') ? "#Entity\n$line" : line }
filter { line -> line.contains('private Long id') ? "#Id\n#GeneratedValue(strategy=GenerationType.AUTO)\n$line" : line } }
}
}
So I'm actually asking myself the same question.
I found an example but the guy is simply re-defining his POJOs and providing a way to adapt the generated ones to the handwritten ones. Tedious and not evolutive.
Globally this could be hard because I'm not sure there is a way in your swagger to decide which POJO will be JPA enabled and maybe you don't want them all in your DB (?) Also, how to you tag the id in swagger?
If you know of such a way, you can always modify the mustache (pojo.mustache I guess) to give you the annotations you're missing.
I used Jhipster to generate entities in my app. Here is jdl file content :
entity GameGenre {
name String
}
entity Game {
name String,
description String,
coverImage String,
logo String
}
entity Tournament {
}
// defining multiple OneToMany relationships with comments
relationship OneToMany {
Game{tournaments} to Tournament
}
relationship ManyToMany {
Game{genres} to GameGenre{games}
}
paginate Game with infinite-scroll
paginate GameGenre, Tournament with pagination
dto * with mapstruct
// Set service options to all except few
service all with serviceImpl
filter *
// Set an angular suffix
// angularSuffix * with mySuffix
Problem occurs in classes with suffix QueryService so GameGenreQueryService, GameQueryService and TournamentQueryService. Issue occurs in method : createSpecification that Jhipster generate :
/**
* Function to convert TournamentCriteria to a {#link Specifications}
*/
private Specifications<Tournament> createSpecification(TournamentCriteria criteria) {
Specifications<Tournament> specification = Specifications.where(null);
if (criteria != null) {
if (criteria.getId() != null) {
specification = specification.and(buildSpecification(criteria.getId(), Tournament_.id));
}
if (criteria.getGameId() != null) {
specification = specification.and(buildReferringEntitySpecification(criteria.getGameId(), Tournament_.game, Game_.id));
}
}
return specification;
}
Tournament_ cannot be resolved to a variable,
Game_ cannot be resolved to a variable
I don't know what does this method expect but this is error that occur. Is this my mistake on Jhipster ?
Your project needs to compile to create meta-classes for your java-class specifications.
Here you can run this command to create:
./mvn clean compile
after that, for defining your metaclasses in your IntelliJ IDE you need to add this plugin in your maven, Pom.xml file:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>add-source</id>
<goals>
<goal>add-source</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<sources>
<source>target/generated-sources/annotations</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
I'm bootstrapping a database using hibernate-maven-plugin, using models that it scans in the maven module it's executed in.
Unfortunately, it stops when hibernate throws this:
org.hibernate.tool.schema.spi.SchemaManagementException: SQL strings added more than once for: reference_data_source.UK-UK_9ec6wdvyj3mjagiptcnrq2txv
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.checkExportIdentifier(SchemaCreatorImpl.java:299)
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:255)
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:128)
at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:199)
So, I have two persistence units, and some tables exists in both. Hibernate seems to interpret this like the same table though, so when it tries to store the same index, but for another schema, it fails thinking it is a duplicate. Their code can be found here.
I'm not sure how to approach this, anyway to configure hibernate hbm2ddl to keep track of these different peristence units?
This is the configuration for the hibernate-maven-plugin:
<plugin>
<groupId>de.juplo</groupId>
<artifactId>hibernate-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<detail>true</detail>
<persistenceUnit>mainPersistenceUnit</persistenceUnit>
<driver>com.mysql.jdbc.Driver</driver>
<dialect>org.hibernate.dialect.MySQL5Dialect</dialect>
<force>true</force>
<url><![CDATA[jdbc:mysql://localhost/auto_bootstrap_schema]]></url>
<username>user</username>
<password>pass</password>
</configuration>
<executions>
<execution>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
</dependencies>
</plugin>
I had the same problem. The reason in my case was that I had three entities starting with same prefix name and a OneToMany relation to the each more specialized one:
Person
PersonCard
PersonCardLayout
Renaming my model to this solved my problem:
Person
Card
Layout
This seems to be a bug in Hibernate.
i have the same problem, looks like a bug in:
org.hibernate.mapping.UniqueKey#getExportIdentifier
#Override
public String getExportIdentifier() {
return StringHelper.qualify( getTable().getName(), "UK-" + getName() );
}
because the identifier was build only from table name but without schema/catalog of the table.
Therefore, if you have to entities with same table name but different schema and in these entities two properties with same name and "unique = true" you will drop into the bug.
Another solution to this is to make use of #Table.
For example:
#Table(name="PERSON")
This happened to me when I had two classes representing two entities (#Entity) as follows:
#Entity
public class User {...}
#Entity
public class UserRoles {...}
I fixed this error by specifying the table name as follows:
#Entity
#Table(name="USER")
public class User {...}
And:
#Table(name="USER_ROLES")
#Entity
public class UserRoles {...}
Not sure if this is the same as what I ran into, but I had the same error issue with base class marked with #Entity annotation: changing to #MappedSuperclass removed the error.
Good Luck,
Ray
I'm using Apache Olingo as an OData client for a Java SDK that I will provide for a RESTful OData API. In the SDK I want to be able to have strongly typed classes to represent the OData entities. I'm having trouble implementing this easily and thus feel like I'm missing a different strategy here.
The Olingo way seems to be to get an ODataClient object which provides the user with a bunch of useful methods for interacting with the API. The ODataClient is using a bunch of factory methods to build my request. For instance, this is the code I used to get the Customers from the Northwind sample OData service. client is an an instance of the necessary ODataClient class.
String serviceRoot = "http://services.odata.org/V4/Northwind/Northwind.svc";
URI customersUri = client.newURIBuilder(serviceRoot)
.appendEntitySetSegment("Customers").build();
ODataRetrieveResponse<ODataEntitySetIterator<ODataEntitySet, ODataEntity>> response =
client.getRetrieveRequestFactory().getEntitySetIteratorRequest(customersUri).execute();
if (response.getStatusCode() >= 400) {
log("Error");
return;
}
ODataEntitySetIterator<ODataEntitySet, ODataEntity> iterator = response.getBody();
while (iterator.hasNext()) {
ODataEntity customer = iterator.next();
log(customer.getId().toString());
}
I'd like to end up with a strongly typed entity from the iterator (i.e. Customer customer = iterator.next()). However, I'm not sure how to actually do that.
If I create a Customer class that extends ODataEntity and attempt to perform a cast such as Customer customer = (Customer) iterator.next() then I get a ClassCastException since the objects in the iterator are just ODataEntity objects and know nothing about the Customer subclass.
My next thought was to introduce generics but doing so will require what seems like a good amount of modification to the Olingo library which leads me to think that there is a better way to do this.
I'm using the development version of Apache Olingo 4 since the OData service must use OData 4.
What am I missing?
It is not really advertised, but there is nowadays a POJO generator in Olingo, in the source tree at ext / pojogen-maven-plugin. Unfortunately for using the POJOs another layer with a different programming model is added, which holds entities cached in memory and syncs with OData service on a flush operation. I would be really interested in adapting it to a more conventional request/response model based on Olingos Request Factories.
However, you could try it out. In your pom include pojogen-maven-plugin and odata-client-proxy.
The POJO generation can be triggered in the pom with
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.olingo</groupId>
<artifactId>pojogen-maven-plugin</artifactId>
<version>4.2.0-SNAPSHOT</version>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
<localEdm>${basedir}/src/main/resources/metadata.xml</localEdm>
<basePackage>odata.test.pojo</basePackage>
</configuration>
<executions>
<execution>
<id>v4pojoGen</id>
<phase>generate-sources</phase>
<goals>
<goal>v4pojoGen</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
For the experiment I stored the EDM Metadataof the Olingo Car example service at src/main/resources/metadata.xml. Somehow the plugin wants to create an inbetween ojc-plugin folder and I just moved the generated Java code at the proper place manually.
At that point you have a Service.java and Java interfaces for each entity or complex type in the EDM model.
You can make use of it to read some entities like this
Service<EdmEnabledODataClient> service = odata.test.pojo.Service.getV4("http://localhost:9080/odata-server-sample/cars.svc");
Container container = service.getEntityContainer(Container.class);
for (Manufacturer m : container.getManufacturers()) {
System.out.println(m.getName());
}