Spring data JPA and Geometry type - spring-boot

I am developing an application that will run on both MySql and MS SQL.
I have a field that is "geometry" type for spatial.
By using:
#Column(columnDefinition = "geometry")
private Point geometry;
(point is org.springframework.data.geo.Point)
Hibernate creates the field properly (hbm2ddl).
But inserting any point does not work.
I get : Data truncation: Cannot get geometry object from data you send to the GEOMETRY field
I use spring-boot-jpa-starter.. and not direct hibernate.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.2.Final</version>
</dependency>
Regards,
Ido

Hello I have successfully mapped a point in JPA. Here's what I did:
I have this on Maven:
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.5.Final</version>
</dependency>
I have this on my entity:
#Column(name = "locationpoint", columnDefinition = "POINT")
private Point locationpoint;
I have this on my application.properties:
# needed for Location domain class
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect
I can get the value using this:
locationRepository.findOne((long) 1).getLocationpoint().getX();
locationRepository.findOne((long) 1).getLocationpoint().getY();
I based my solution from here Matti Tahvonen's example:
https://github.com/mstahv/spring-boot-spatial-example
Hope this helps.

Related

Function "ST_WITHIN" not found in Spring Boot Application using h2 In-Memory Database and Hibernate Spatial

In a Spring Boot application (h2 in-memory database + Hibernate Spatial) in a Junit test, I'm getting error "Function "ST_WITHIN" not found" for a "within" query
pom.xml:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
</dependency>
test/resources/application.properties:
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=va
spring.jpa.database=h2
spring.jpa.database-platform=org.hibernate.spatial.dialect.h2geodb.GeoDBDialect
LocationRepository.java
#Query(value = "select l from Location l where within(l.position, :box) = true")
List<Location> findByPositionWithin(#Param("box") org.locationtech.jts.geom.Geometry box);
LocationEntity.java
#Column(columnDefinition = "GEOMETRY")
private org.locationtech.jts.geom.Point position;
Obviously, the alias ST_WITHIN is missing.
Any ideas how to fix this?

How to cache PageImpl with Spring Data Geode?

When trying to cache a PageImpl response from a Spring Data JpaRepository using Spring Data Geode, it fails to cache the result with the following error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.PageImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.data.domain.PageImpl.<init>()
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:127) ~[spring-beans-5.0.6.RELEASE.jar:5.0.6.RELEASE]
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:86) ~[spring-data-commons-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.springframework.data.gemfire.mapping.MappingPdxSerializer.fromData(MappingPdxSerializer.java:422) ~[spring-data-gemfire-2.0.7.RELEASE.jar:2.0.7.RELEASE]
at org.apache.geode.pdx.internal.PdxReaderImpl.basicGetObject(PdxReaderImpl.java:741) ~[geode-core-9.1.1.jar:?]
at org.apache.geode.pdx.internal.PdxReaderImpl.getObject(PdxReaderImpl.java:682) ~[geode-core-9.1.1.jar:?]
at org.apache.geode.internal.InternalDataSerializer.readPdxSerializable(InternalDataSerializer.java:3054) ~[geode-core-9.1.1.jar:?]
It looks like the MappingPdxSerializer looks for a default constructor but doesn't find it for a PageImpl class.
Here is maven pom for the dependencies I have:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.BUILD-SNAPSHOT</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The JpaRepository I am using is:
#RepositoryRestResource
public interface RecordRepository extends JpaRepository<Record, Long>
{
#Override
#CacheEvict(cacheNames = { "Records" })
<S extends Record> S save(S s);
#Override
#Cacheable(value = "Records")
Optional<Record> findById(Long id);
#Override
#Cacheable(value = "Records", key = "#pageable.pageNumber + '.' + #pageable.pageSize + '.records'")
Page<Record> findAll(Pageable pageable);
#Override
#Cacheable(value = "Records")
Record getOne(Long aLong);
}
The code used to invoke a repository paged result is:
int PAGE=0,PAGE_SIZE=100;
Page<Record> recordPage;
do {
recordPage = recordRepository.findAll(PageRequest.of(PAGE, PAGE_SIZE));
log.info("Retrieved page: [{}]", recordPage);
} while (recordPage.hasNext());
I feel like it maybe a possible bug with the MappingPdxSerializer, but I'm not 100% sure. Any help in resolving this issue would be awesome!
Thanks
Why do you feel this is a possible bug with Spring Data Geode's (SDG) o.s.d.g.mapping.MappingPdxSerializer?
It is quite common, and even expected, that not all objects passed through SDG's MappingPdxSerializer will have a default (i.e. public, no-arg) constructor.
When using such types in your application (e.g. like the SD PageImpl class) and an instance of that type is read from Apache Geode (e.g. get(key)), the object is de-serialized and reconstructed on the (Region) data access operation (providing Apache Geode's read-serialized configuration attribute is not set to true; which cause you other problems and not recommended in this case), then you need to register an EntityInstantiator that informs SDG's MappingPdxSerializer how to instantiate the object, using an appropriate constructor.
The "appropriate" constructor is determined by the persistent entity's PreferredConstructor, which is evaluated during type evaluation by the SD Mapping Infrastructure, and can be specified with the #PersistenceContructor annotation, if necessary. This is useful in cases where you are using 1 of SD's canned EntityIntantiator types, e.g. ReflectionEntityInstantiator, and your application domain type has more than 1 non-default constructor.
Therefore, you can register 1 or more EntityInstantiator objects per application domain object by type using the EntityIntantiatiors composite class, perhaps with a "mapping" between application domain object Class type (e.g. Page) and EntityInstantiator, and then register the EntityInstantiators on SDG's MappingPdxSerializer.
Of course, you need to make sure that custom configured MappingPdxSerializer gets used by Apache Geode...
#Configuration
class ApacheGeodeConfiration {
#Bean
MappingPdxSerializer pdxSerializer() {
Map<Class<?>, EntityInstantiator> customInstantiators = new HashMap<>();
customInstantiators.put(Page.class, new MyPageEntityInstantiator());
customInstantiators.put...
MappingPdxSerializer pdxSerializer =
MappingPdxSerializer.newMappingPdxSerializer();
pdxSerializer.setGemfireInstantiators(
new EntityInstantiators(customInstantiators));
return pdxSerializer;
}
#Bean
CacheFactoryBean gemfireCache(MappingPdxSerializer pdxSerializer) {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setPdxSerializer(pdxSerializer);
gemfireCache.set...
return gemfireCache;
}
...
}
Hope this helps!
-j

"IllegalArgumentException: At least one JPA metamodel must be present" - when trying to connect application both to mongo and sql

We have a Spring application that connects with no problems to a MongoDB, with #Autowire and all the rest.
Now we also need the app to connect also to an SQL database.
So we crated an #entity class:
#Entity(name = "SqlCarRecord")
#Table(name = "Cars")
final public class SqlCarRecord {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name", nullable = false)
private String name;
....
And a #repository interface:
#Repository
public interface SqlCarsRepository extends JpaRepository<SqlCarRecord, Long> {
...
And a #Configuraion class like the example here https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-one-configuration/
And in the applicationContext we added
<jpa:repositories base-package="path.to.interface.package" />
In the pom.xml we already have
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
and we added:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.0.0.M3</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.1.0</version>
</dependency>
<!-- DataSource (HikariCP) -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.6.2</version>
</dependency>
<!-- JPA Provider (Hibernate) -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.6.RELEASE</version>
</dependency>
<!-- adding this to avoid "java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal" -->
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
<!-- adding this to avoid "ClassNotFoundException: org.springframework.data.util.CloseableIterator" -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.13.6.RELEASE</version>
</dependency>
And in the #Service class we added:
....
#Autowired
private SqlCarsRepository carsRepository;
The project is built successfully, but when we try to run it, we get this error:
Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'jpaMappingContext': Invocation of init method failed; nested
exception is java.lang.IllegalArgumentException: At least one JPA metamodel
must be present!
Some of the things We tried:
change the different versions of spring in the pom,
we tried to comment some of them,
we tried to change the interface to extend CrudRepository,
tried to add an empty constructor to the entity and some other things
with no luck.
Will appriciate help.
Thanks in advance.
I solved the same error message by changing the #SpringBootApplication annotation to this:
#SpringBootApplication(exclude = {JndiConnectionFactoryAutoConfiguration.class,DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,JpaRepositoriesAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
If you are using the #EnableAutoConfiguration directly, try this:
#EnableAutoConfiguration(exclude = {JndiConnectionFactoryAutoConfiguration.class,DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,JpaRepositoriesAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class})
It seems that the root problem is that the Spring Boot is trying to add something that is already on the classpath.
Most of answer taken from https://stackoverflow.com/a/30597861/7470360

JPA Hibernate + UCP Oracle. Query executed from save method does not use the index of the table

I'm using the interface CRUDRepository in order to use the save method in other class where Repository is injected.
This method does an insert and a select for retrieve this object inserted from database, I mean.
The query executed is quite simple:
select auditoriab0_.adb_seqitm as adb_seqitm1_1_0_,
auditoriab0_.adb_codprv as adb_codprv2_1_0_, auditoriab0_.adb_ideses as adb_ideses3_1_0_,
auditoriab0_.adb_locata as adb_locata4_1_0_, auditoriab0_.adb_rqores as adb_rqores5_1_0_,
auditoriab0_.adb_rstime as adb_rstime6_1_0_, auditoriab0_.adb_subprv as adb_subprv7_1_0_,
auditoriab0_.adb_swierr as adb_swierr8_1_0_, auditoriab0_.adb_tiptrz as adb_tiptrz9_1_0_,
auditoriab0_.adb_ubitrz as adb_ubitrz10_1_0_, auditoriab0_.adb_xmltxt as adb_xmltxt11_1_0_
from nwt00.auditoria_bus_gsi auditoriab0_ where auditoriab0_.adb_seqitm=:p1
Where adb_seqitm column has and index on it (It's the table's primary key).
If this query is executed on SQLDeveloper, for instance, the explain plan is the correct one (access by rowid).
However, if this query is executed by hibernate, the result is a full scan.
Could you help me with this issue? I will be grateful because I don't have seen a real solution on internet for this specific problem.
Thank you in advance.
This behaviour happens with the ucp (universal connection pool) pool. My database bean configuration is the next (variables are setted by application.properties file):
UniversalConnectionPoolManager mgr;
try {
mgr = UniversalConnectionPoolManagerImpl. getUniversalConnectionPoolManager();
mgr.destroyConnectionPool("hotels");
} catch (UniversalConnectionPoolException e) {
}
PoolDataSourceImpl poolDataSource = (PoolDataSourceImpl) PoolDataSourceFactory.getPoolDataSource();
poolDataSource.setUser(userName);
poolDataSource.setPassword(passWord);
poolDataSource.setURL(url);
poolDataSource.setConnectionFactoryClassName(driver);
poolDataSource.setConnectionPoolName("hotels");
poolDataSource.setInitialPoolSize(initialNumConnections);
poolDataSource.setMinPoolSize(minNumConnections);
poolDataSource.setMaxPoolSize(maxNumConnections);
poolDataSource.setMaxConnectionReuseTime(reconnectTime);
poolDataSource.setMaxConnectionReuseCount(maxReconnectCount);
poolDataSource.setTimeToLiveConnectionTimeout(timeToLive);
poolDataSource.setConnectionWaitTimeout(connectWaitTimeOut);
poolDataSource.setValidateConnectionOnBorrow(true);
poolDataSource.setInactiveConnectionTimeout(inactiveConnectionTimeOut);
Properties properties = new Properties();
properties.put("v$session.program", "xxxx");
properties.put("defaultNChar", "false");
poolDataSource.setConnectionProperties(properties );
I'm using Spring Boot + Spring Data JPA. These are my dependencies of my pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4.0</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ucp</artifactId>
<version>11.2.0.4.0</version>
</dependency>
#krokodilko As you anticipated, the error was between database type and java type. In DDBB, this field is a String (varchar2(15)). In Java, this field is mapped with a long type. I guess hibernate or database is doing a conversion which breaks the index. I have changed the java type by String type and query is working successfully. Explain plan is correct.

What is the work around for Hibernate 4 persistence support for org.joda.time.contrib.hibernate.PersistentDateTime

Hi All I am new to Spring and am building application using the following dependencies
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.7.Final</version>
</dependency>
<spring.framework.version>3.1.2.RELEASE</spring.framework.version>
I am not able to persist the objects with fields with datatype DateTime from the class org.joda.time.contrib.hibernate.PersistentDateTime.
#Column(name = "LAST_MODIFIED_DATE")
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
public DateTime getLastModifiedDate() {
return lastModifiedDate;
}
Can anybody suggest how to use the joda DateTime.
I had been trying this for entire day finally got the solution as the following. org.joda.time.contrib.hibernate.PersistentDateTime class persistence is not supported by higher versions of hibernate. Rather we use some very specific libraries like the
<dependency>
<groupId> org.jadira.usertype </groupId>
<artifactId> usertype.core </artifactId>
<version> 3.0.0.CR3 </version>
</dependency>
This is how we can persist the data in the database for audit purpose.
#Column(name = "CREATED_DATE")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
public DateTime getCreatedDate() {
return createdDate;
}

Resources