Is there any rule that I can use for restricting following if statements :
if ( null == name ) {
...
}
Basically, null should be always on the right side of statement e.g.
if ( name == null ) {
...
}
Sevntu has a custom check called AvoidConstantAsFirstOperandInConditionCheck which does what you want.
$ cat TestClass.java
public class TestClass {
void method() {
if ( null == name ) {} // violation
if ( name == null ) {} // OK
}
}
$ cat TestConfig.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="charset" value="UTF-8"/>
<module name="TreeWalker">
<module name="com.github.sevntu.checkstyle.checks.coding.AvoidConstantAsFirstOperandInConditionCheck" />
</module>
</module>
$ java -jar checkstyle-8.9-sevntu-1.29.0-all.jar -c TestConfig.xml TestClass.java
Starting audit...
[ERROR] TestClass.java:3: Constant have to be second operand of '=='. [AvoidConstantAsFirstOperandInCondition]
Audit done.
Checkstyle ends with 1 errors.
Related
I am learning Java EE and for 2 days already I've been struggling with configuration of Hibernate to work with MySQL database on a TomEE server in a simple Java EE web application.
Hibernate version: 5.4.10.Final (core and entity-manager dependencies)
Java EE API: 8.0
MySQL version: 8.0.19
TomEE version: 8.0.1 (TomEE Embedded in tomee-embedded-maven-plugin)
I have 2 simple entities: Car and Seat, with the uni-directional #OneToMany relation from Car to Seat(s). Color and EngineType are plain enums, while Specification is a value object for these 2 enums). NOTE: FetchType.EAGER is used in the #OneToMany for learning purposes, I am familiar that this is not a good solution normally.
When I try to configure the persistence.xml file, alghouth specifying everything "as for MySQL", it seems that Hibernate still uses the default HSQLDB syntax/dialect/engine and as a result, I recieve errors during schema creation:
[INFO] TomEE embedded started on localhost:8080
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
Hibernate: alter table Seat drop foreign key FKkkm9pdx9e1t9jva76n9tqhhqv
mar 06, 2020 1:48:31 PM org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
WARN: GenerationTarget encountered exception accepting command : Error executing DDL "alter table Seat drop foreign key FKkkm9pdx9e1t9jva76n9tqhhqv" via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table Seat drop foreign key FKkkm9pdx9e1t9jva76n9tqhhqv" via JDBC Statement
(...)
Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: PUBLIC.SEAT
(...)
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: PUBLIC.SEAT // what is going on here???
and for later Hibernate SQL commands while creating DDL, I have also:
Hibernate: create table Car (identifier bigint not null auto_increment, color varchar(255), engineType varchar(255), primary key (identifier)) engine=InnoDB
mar 06, 2020 1:48:31 PM org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
WARN: GenerationTarget encountered exception accepting command : Error executing DDL "create table Car (identifier bigint not null auto_increment, color varchar(255), engineType varchar(255), primary key (identifier)) engine=InnoDB" via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table Car (identifier bigint not null auto_increment, color varchar(255), engineType varchar(255), primary key (identifier)) engine=InnoDB" via JDBC Statement
(...)
Caused by: java.sql.SQLSyntaxErrorException: unexpected token: AUTO_INCREMENT
(...)
Caused by: org.hsqldb.HsqlException: unexpected token: AUTO_INCREMENT // definitely something messed up, this is a correct MySQL token
When I omit all "MySQL stuff" (driver and dialect), and make Hibernate use default HSQLDB, it works fine... The DDL for HSQLDB is created well.
I tried many different configurations and replacements googling it over the web and SO, but not found any hint why Hibernate still uses non-MySQL syntax (but I am not 100% sure that this is the direct cause of the issue).
I attempted to specify the datasource in resources.xml file under webapp, but it doesn't change anything. Additionally, I checked if HSQLDB could be excluded from Maven build, but it ships with hibernate-core, so it's not easily achievable and perhaps could also not help.
I have previously used Hibernate with Spring and SpringBoot, but with Java EE I am totally lost here, that's why I asked the question.
Could anyone help with the issue and give some advices on the correct configuration of all this?
My persistence.xml under resources/META-INF looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.2"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="my-persistence-unit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:openejb/Resource/myJtaDatabase</jta-data-source>
<!-- Entity classes -->
<class>com.example.javaeecourse.entity.Car</class>
<class>com.example.javaeecourse.entity.Seat</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/javaeecourse?serverTimezone=UTC" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="admin" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="tomee.jpa.factory.lazy" value="true" />
<!--<property name="tomee.jpa.cdi=false" value="false" />-->
</properties>
</persistence-unit>
</persistence>
Car entity:
package com.example.javaeecourse.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import static com.example.javaeecourse.entity.Car.FIND_ALL;
#Getter
#Setter
#Entity
#Table(name = "cars")
#NamedQuery(name = FIND_ALL, query = "SELECT car FROM Car car")
#NoArgsConstructor
public class Car {
public static final String FIND_ALL = "Car.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long identifier;
#Enumerated(EnumType.STRING)
private Color color;
#Enumerated(EnumType.STRING)
private EngineType engineType;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "car", nullable = false)
private Set<Seat> seats = new HashSet<>();
}
Seat entity:
package com.example.javaeecourse.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
#Entity
#Table(name = "seats")
#NoArgsConstructor
#Getter
#Setter
public class Seat {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String seatMaterial;
public Seat(String seatMaterial) {
this.seatMaterial = seatMaterial;
}
}
CarManufacturer class (#Stateless EJB, where EntityManager is called):
package com.example.javaeecourse.boundary;
import com.example.javaeecourse.control.CarFactory;
import com.example.javaeecourse.entity.Car;
import com.example.javaeecourse.entity.CarCreatedEvent;
import com.example.javaeecourse.entity.Specification;
import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
#Stateless
public class CarManufacturer {
#Inject
CarFactory carFactory;
#Inject
Event<CarCreatedEvent> carCreatedEvent;
#PersistenceContext
EntityManager entityManager;
public Car manufactureCar(Specification specification) {
Car car = carFactory.createCar(specification);
entityManager.persist(car);
carCreatedEvent.fire(new CarCreatedEvent(car.getIdentifier()));
return car;
}
public List<Car> retrieveCars() {
return entityManager.createNamedQuery(Car.FIND_ALL, Car.class).getResultList();
}
}
CarFactory class, which instantiates the entity:
package com.example.javaeecourse.control;
import com.example.javaeecourse.entity.*;
import javax.inject.Inject;
public class CarFactory {
#Inject
#DefaultCarColor
Color randomCarColor;
#Inject
#DefaultCarEngineType
EngineType randomCarEngineType;
public Car createCar(Specification specification) {
Car car = new Car();
car.setColor(specification.getColor() == null ? randomCarColor : specification.getColor());
car.setEngineType(specification.getEngineType() == null ? randomCarEngineType : specification.getEngineType());
Seat seat = new Seat("Leather");
car.getSeats().add(seat);
return car;
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>javaeecourse</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Java EE Course App</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<finalName>javaeecourse</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.apache.tomee.maven</groupId>
<artifactId>tomee-embedded-maven-plugin</artifactId>
<version>8.0.1</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
I will be grateful for any help.
Thanks to the hint provided by #areus in the question comment, I was able to resolve the case. I am posting an answer here if anyone had a similar issue in the future.
There was 1 major issue and 1 "bad practice" issue.
The main problem was that I was using a JTA transaction type and referenced the jta-data-source by JNDI name, but the resources.xml was located under webapp instead of resources/META-INF.
After I moved the resource.xml to the META-INF, the database could be properly created and entities were persisted.
Additionally, in my configuration, I have used a deprecated JDBC Driver for MySQL 8. According to this doc, since MySQL 8.0, the driver is now com.mysql.cj.jdbc.Driver, not com.mysql.jdbc.Driver.
I also removed the unnecessary properties, so the config is now quite clear and everything works fine.
resources/META-INF/persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.2"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="my-persistence-unit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/javaeecourse</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="tomee.jpa.factory.lazy" value="true"/>
</properties>
</persistence-unit>
</persistence>
resources/META-INF/resources.xml
<?xml version="1.0" encoding="UTF-8"?>
<tomee>
<Resource id="jdbc/javaeecourse" type="javax.sql.DataSource">
JdbcDriver = com.mysql.cj.jdbc.Driver
JdbcUrl = jdbc:mysql://localhost:3306/javaeecourse?serverTimezone=UTC
UserName = root
Password = admin
jtaManaged = true
</Resource>
</tomee>
Here is also a great article regarding the JTA/RESOURCE_LOCAL transaction types as well as jta-data-source and non-jta-data-source configuration, which helped me understand the details.
I'm trying to configure Hibernate JPA to access database. Without using Hibernate JPA, It accesses to database well, but when using Hibernate JPA it does not.
I'm following this tutorial:
https://www.playframework.com/documentation/2.5.x/JavaJPA
These are my steps:
build.sbt
//Hibernate JPA
libraryDependencies ++= Seq( javaJpa, "org.hibernate" % "hibernate-entitymanager" % "5.1.0.Final" // replace by your jpa implementation )
//JPA
PlayKeys.externalizeResources := false
//Driver for mysql
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.36"
conf/application.conf
db {
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
default.driver = "com.mysql.jdbc.Driver"
default.url = "jdbc:mysql://localhost:3306/sakila"
default.username = root
default.password = "root"
default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit
default.logSql=true
}
conf/META_INF/persistence.xml
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>DefaultDS</non-jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
</properties>
</persistence-unit>
</persistence>
Error messages:
! #70fdppp3i - Internal server error, for (GET) [/count] ->
play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [jpa]]
at play.api.Configuration$.configError(Configuration.scala:154)
at play.api.Configuration.reportError(Configuration.scala:806)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:48)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:42)
at scala.collection.immutable.List.foreach(List.scala:381)
at play.api.db.DefaultDBApi.connect(DefaultDBApi.scala:42)
at play.api.db.DBApiProvider.get$lzycompute(DBModule.scala:72)
at play.api.db.DBApiProvider.get(DBModule.scala:62)
at play.api.db.DBApiProvider.get(DBModule.scala:58)
at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
Caused by: play.api.Configuration$$anon$1: Configuration error[either dataSource or dataSourceClassName is required]
at play.api.Configuration$.configError(Configuration.scala:154)
at play.api.PlayConfig.reportError(Configuration.scala:996)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:70)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:44)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:42)
Caused by: java.lang.IllegalArgumentException: either dataSource or dataSourceClassName is required
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:785)
at play.api.db.HikariCPConfig.toHikariConfig(HikariCPModule.scala:141)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:57)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:54)
at scala.util.Try$.apply(Try.scala:192)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:54)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
Error message on screen:
How to solve it?
I'm using Play framework 2.5
I think your jpa.default property is in wrong place. Try like this:
db {
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
default.driver = "com.mysql.jdbc.Driver"
default.url = "jdbc:mysql://localhost:3306/sakila"
default.username = root
default.password = "root"
default.jndiName=DefaultDS
default.logSql=true
}
jpa.default=defaultPersistenceUnit
The Jetty embedded has a jetty.xml for the configuration. This configuration has a mysql jndi-connection.
When I run jetty with gradle, it throws an exception:
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
at org.eclipse.jetty.util.Loader.loadClass(Loader.java:86)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.nodeClass(XmlConfiguration.java:364)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:754)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.itemValue(XmlConfiguration.java:1125)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.value(XmlConfiguration.java:1030)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:775)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:423)
at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:298)
at org.eclipse.jetty.xml.XmlConfiguration.configure(XmlConfiguration.java:248)
at org.eclipse.jetty.xml.XmlConfiguration$configure.call(Unknown Source)
at com.sahlbach.gradle.plugins.jettyEclipse.JettyEclipseRun.applyJettyXml(JettyEclipseRun.groovy:533)
at com.sahlbach.gradle.plugins.jettyEclipse.JettyEclipseRun.startJetty(JettyEclipseRun.groovy:318)
This is the line of jetty.xml where the exception is thrown:
<New id="relevante" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/Relevante</Arg>
<Arg>
<New id="relevanteDataSource" class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="url">jdbc:mysql://localhost:3306/xxxx</Set>
<Set name="user">xxxx</Set>
<Set name="password">xxxx</Set>
</New>
</Arg>
</New>
The MySQL connector is a dependency of gradle and I don't know if I need to place the connector into a local address (in addition to as dependency in gradle).
jettyEclipse {
additionalRuntimeJars = files( new File("$rootDir/src/main/webapp/WEB-INF/lib/mysql-connector-java-5.0.8-bin.jar") )
warFile = file("$rootDir/build/libs/relevanteme.war")
jettyConfig = file("$rootDir/jetty.xml")
contextPath = ""
automaticReload = "true"
scanIntervalInSeconds = 5
webDefaultXml = file("$rootDir/webdefault.xml")
}
Thanks!!
What's the task to run jetty? Do you know if there is a separate configuration for that and does it extends from compile?
The solution's to have two xml files for server configuration. One of these two files will be jetty.xml which will have all the server configuration. The other file will be jetty-env.xml with webApp configuration and connection to the database (this file has to be in webapp/WEB-INF/).
More information in this repository.
I am running arquillian tests with junit and gradle. How do I choose which container gets started?
At the moment I am defining the container qualifier in a file with name arquillian.launch.
My arquillian.xml looks as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<arquillian ...>
<container qualifier="glassfish3-embedded" default="true">
<configuration>
...
</configuration>
</container>
<container qualifier="wls">
<configuration>
...
</configuration>
</container>
</arquillian>
My build.gradle looks as follows:
[...]
configurations {
glassfishEmbeddedTestRuntime { extendsFrom testRuntime }
weblogic10RemoteTestRuntime { extendsFrom testRuntime }
}
dependencies {
glassfishEmbeddedTestRuntime group: 'org.jboss.arquillian.container', name: 'arquillian-glassfish-embedded-3.1', version: '1.0.0.CR4'
glassfishEmbeddedTestRuntime group: 'org.glassfish.main.extras', name: 'glassfish-embedded-all', version: libraryVersions.glassfish
weblogic10RemoteTestRuntime group: 'org.jboss.arquillian.container', name: 'arquillian-wls-remote-10.3', version: '1.0.0.Alpha2'
}
task glassfishEmbeddedTest(type: Test)
task weblogic10RemoteTest(type: Test)
tasks.withType(Test).matching({ t-> t.name.endsWith('Test') } as Spec).each { t ->
t.classpath = project.configurations.getByName(t.name + 'Runtime') + project.sourceSets.main.output + project.sourceSets.test.output
}
How can I expand the definition for weblogic10RemoteTest, so that I can choose the container, and I don't have to edit the arquillian.launch file or the arquillian.xml file by changing the xml before executing the tests?
I thought about doing it like here: https://github.com/seam/solder/blob/develop/testsuite/pom.xml#L123
But I don't know the equivalent of this statement in gradle.
The POM you linked to sets system properties for the JVM running the tests. You can do the same in Gradle by configuring your Test task(s):
test { // or: tasks.withType(Test) {
systemProperty "one", "foo"
systemProperty "two", "bar"
}
(Note that Gradle always runs tests in a separate JVM.)
For further information, see Test in the Gradle Build Language Reference.
I'm creating some simple webpage with Spring MVC, Hibernate4 and MySQL5. One of models I use contains BLOB value (byte[]). When I try to persist that model with entityManager.persist()
I get MySQLSytnaxException. Actually there are more problems with current configuration, such as persist/merge/remove ignoring #Transactional annotation, but this one is the most critical.
I already tried using session.save(object); or replacing byte[] by Blob. Still the same result. All working examples I found use completely diffirent approach - e.g. they use HibernateSessionManager and HibernateTransactionManager instead of JPA ones - and I would like to found solution that doesn't require complete change in how I persist entities, when I'm still not sure that it would help.
Could You tell me what mistakes I made in code/configuration/assumptions?
Beginning of a stack trace together with Hibernate trace:
Hibernate:
insert
into
updates
(changelog, added, developmentVersion, filedata, filedataType, major, minor, nightly, release, package, type, uploader, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
22:53:10,888 TRACE BasicBinder:83 - binding parameter [1] as [VARCHAR] - sdfsd
22:53:10,891 TRACE BasicBinder:71 - binding parameter [2] as [DATE] - <null>
22:53:10,894 TRACE BasicBinder:83 - binding parameter [3] as [BOOLEAN] - false
22:53:10,898 TRACE BasicBinder:83 - binding parameter [4] as [BLOB] - javax.sql.rowset.serial.SerialBlob#298fd36c
22:53:10,924 TRACE BasicBinder:83 - binding parameter [5] as [VARCHAR] - image/png
22:53:10,926 TRACE BasicBinder:83 - binding parameter [6] as [INTEGER] - 1
22:53:10,928 TRACE BasicBinder:83 - binding parameter [7] as [INTEGER] - 0
22:53:10,935 TRACE BasicBinder:83 - binding parameter [8] as [INTEGER] - 0
22:53:10,936 TRACE BasicBinder:83 - binding parameter [9] as [INTEGER] - 0
22:53:10,939 TRACE BasicBinder:83 - binding parameter [10] as [INTEGER] - 36
22:53:10,941 TRACE EnumType:292 - Binding {0} to parameter: {1}
22:53:10,944 TRACE BasicBinder:83 - binding parameter [12] as [INTEGER] - 18
22:53:10,955 TRACE BasicBinder:83 - binding parameter [13] as [INTEGER] - 0
22:53:10,998 WARN SqlExceptionHelper:143 - SQL Error: 1064, SQLState: 42000
22:53:10,999 ERROR SqlExceptionHelper:144 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1
22:53:11,027 INFO AbstractBatchImpl:195 - HHH000010: On release of batch it still contained JDBC statements
Nov 07, 2012 10:53:11 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [repoApplication] in context with path [/server] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'release, package, type, uploader, id) values ('sdfsd', null, 0, _binary'‰PNG
' at line 1
beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
...
>
...
<!-- Hibernate configuration -->
<!-- Specifies dataSource object managing connections to database -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<!-- Defines SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
...
<property name="hibernateProperties">
<util:properties location="classpath:Hibernate.properties" />
</property>
</bean>
<!-- Defines TransactionManager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Binds TransactionManager to annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Enables Spring annotations -->
<context:annotation-config />
...
</beans>
Hibernate.properties:
hibernate.database =MYSQL
hibernate.dialect =org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql =true
hibernate.format_sql =true
hibernate.use_sql_comments =true
hibernate.hbm2ddl.auto =update
All tables in MySQL database uses InnoDB engine.
Update.java (model):
import java.sql.Blob;
import java.sql.Date;
import java.sql.SQLException;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.sql.rowset.serial.SerialBlob;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
...
#Entity
#Table(name = "updates")
#VersionNumberCorrect
public class Update {
#Id
#Column(name = "id", unique = true)
private int id;
#NotNull
#ManyToOne
#JoinColumn(name = "package")
private Package thePackage;
#NotNull
#ManyToOne
#JoinColumn(name = "uploader")
private User uploader;
#Column(name = "added")
private Date date;
#Column(name = "changelog")
#NotNull
#NotEmpty
private String changelog;
#Column(name = "major")
private int major;
#Column(name = "minor")
private int minor;
#Column(name = "release")
private int release;
#Column(name = "nightly")
private int nightly;
#Column(name = "developmentVersion")
private boolean developmentVersion;
#Column(name = "type")
#Enumerated(EnumType.ORDINAL)
private EUpdateStrategy type;
#Column(name = "filedata")
#Lob
#Type(type = "blob")
#NotNull
private Blob filedata;
#Column(name = "filedataType")
private String filedataType;
public Update() {
}
...
}
UpdateServiceImp.java (Service):
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
...
#Service
#Transactional
public class UpdateServiceImp implements UpdateService {
#Autowired
private SessionFactory sessionFactory;
#Override
public void persist(Update update) {
getSession().persist(update);
}
#Override
public Update merge(Update update) {
return (Update) getSession().merge(update);
}
#Override
public void remove(Update update) {
getSession().delete(update);
}
...
/**
* Returns new Session instance.
*
* #return new Session
*/
private Session getSession() {
return sessionFactory.getCurrentSession();
}
}
EDIT:
I changed EntityManagerManager usage into Hibernate's SessionFactory - I tried to change that thinking it might help. It didn't, but code got a little bit cleaner :). I've added some information from Hibernate log that might be helpful. I've also added Hibernate.properties content, since this error is most likely something Hibernate configuration related.
Thanks to help of a fellow developer I found out what was wrong: I was using release as a name of one of the properties. I found out that release is a keyword in MySQL, and when it appears in query it makes syntax invalid.
I was honestly surprised to learn that Hibernate does NOT use apostrophes with columns', schemas' and tables' names. I thought it was a common practice to write SQL this way:
INSERT INTO `mySqlTable` VALUES (null, 'value') ;
or
INSERT INTO 'dbo'.'msSqlTable' VALUES (null, 'value');
but Hibernate would do it this way instead:
INSERT INTO mySqlTable VALUES (null, 'value') ;
For MySQL5 the list of reserved words is quite long: http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html
I guess I will have to be more careful with choosing columns' names in the future. Hope that will help someone.