spring boot, jackson and localdate - spring-boot

I use spring boot with mysql
in my application.properties
spring.jpa.generate-ddl=true
spring.jackson.serialization.write-dates-as-timestamps=false
In my build.gradle I have
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-data-rest')
compile('org.springframework.boot:spring-boot-starter-web')
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
In my java class
import java.time.LocalDate;
#Entity
public class WebSite implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long webSiteId;
private LocalDate date;
...
}
When this table is created,
date field is created like a TINYBLOB
Why is not a date

This is not an issue with Jackson, but rather that whatever you are using for ORM doesn't know how to convert a Java LocalDate to a MySQL Date.
There are two ways to do this. If you are using Hibernate, you simply include org.hibernate:hibernate-java8 in your dependencies.
Alternatively, if you want just use JPA, you need to create an Attribute Converter. For example:
#Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
#Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
#Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}
The Attribute Converter will handle converting between a Java LocalDate and MySQL Date.
See: http://www.thoughts-on-java.org/persist-localdate-localdatetime-jpa/

Related

Spring Data JPA findAll() returns empty list from MySQL db

I am newbie in Spring.I am trying to get some data from a MYSQL database. Unfortunately spring data jpa returns empty list. But one record exist in db: How can I access this record?
libraryRepository.java
public interface LibraryRepository extends JpaRepository<Library, String>,LibraryRespositoryCustom{
}
LibraryController.java
#RestController
public class LibraryController {
#Autowired
LibraryRepository repository;
#Autowired
LibraryService libraryService;
#GetMapping("/getAllBooks")
public ResponseEntity<List<Library>> getAllBooks(){
return ResponseEntity.ok(repository.findAll());
}
application.properties
# Datasource
spring.datasource.url=jdbc:mysql://localhost:3306/APIDevelopSpringBoot?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#com.mysql.jdbc.Driver
spring.jpa.generate-ddl=true
# Jpa/Hibernate :
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
#spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto = update
spring.test.database.replace=none
#Generate Logs
logging.file.name=log/application.log
#spring.profiles.active=dev
spring.main.allow-circular-references: true
Library.java
#Data
#Entity
#Table(name="LibraryDemo")
public class Library {
#Column(name="book_name")
private String book_name;
#Id
#Column(name="id")
private String id;
#Column(name="isbn")
private String isbn;
#Column(name="aisle")
private int aisle;
#Column(name="author")
private String author;
}
select library0_.id as id1_0_, library0_.aisle as aisle2_0_, library0_.author as author3_0_, library0_.book_name as book_nam4_0_, library0_.isbn as isbn5_0_ from library_demo library0_
As we can see in this query, it is querying on the table library_demo but you have a table named LibraryDemo. So, you have to change the name to library_demo.
You need to have the table name as library_demo for that to work. Whatever name you give, it gets replaced with _ format.
Try this
#Entity
#Table(name = "library_demo")
public class Library {...}

How to make Set using spring-data-aerospike

Environment:
spring-boot v2.0.4 RELEASE
spring-data-aerospike v2.0.1.RELEASE
java - 8
Here are my application code and properties.
// application.properties
aerospike.hosts=xxx:3000
aerospike.namespace=test
// aerospike configuration class
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(AerospikeConfiguration.AerospikeConfigurationProperties.class)
#EnableAerospikeRepositories(basePackageClassses = TestAeroRepository.class)
public class AerospikeConfiguration extends AbstractAerospikeDataConfiguration {
private final AerospikeConfigurationProperties aerospikeConfigurationProperties;
#Override
protected Collection<Host> getHosts() {
return Host.parseServiceHosts(aerospikeConfigurationProperties.getHosts());
}
#Override
protected String nameSpace() {
return aerospikeConfigurationProperties.getNamespace();
}
#Data
#Validate
#ConfigurationProperties("aerospike")
public static class AerospikeConfigurationProperties {
#NotEmpty
String hsots;
#NotEmpty
String namespace;
}
}
# Entity class
#Value
#Document
#Builder(toBuilder = true)
#AllArgsConstructor
public class testEntity() {
#Id
int id;
#Field
String name;
#Field
String timestamp;
}
#Repository
public interface TestAeroRepository extends AerospikeRepository<TestEntity, Integer> {
}
public interface TestAeroService {
void save();
}
#Service
#RequiredArgsConstructor
public class TestAeroServiceImpl implements TestAeroService {
private final TestAeroRepository testAeroRepository;
#Override
public void save(TestEntity entity) {
testAeroRepository.save(entity);
}
}
I checked Aerospike client connection has no problem.
But error is occurred when save() method is executed.
org.springframework.cglib.core.ReflectUtils.defineClass(Ljava/lang/String;[BLjava/lang/ClassLoader;Ljava/security/ProtectionDomain;Ljava/lang/Class;)Ljava/lang/Class;
Have to make sets before execute the application? I didn't make sets.
Any problem with my code?
You’re using an old version of spring-data-aerospike (2.0.1.RELEASE was released on April 2019) is there any chance you can upgrade to the latest version? 2.4.2.RELEASE
You can see how to setup a simple spring data aerospike application here: https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089
Please share the entire project’s code and the entire exception.
I would look into:
The configuration class (The Aerospike Beans creation).
The content of the testEntity class - are you using #Id annotation on the primary key field?
Extending the repository class with specifying the testEntity object (… extends AerospikeRepository<testEntity, Object> {) you can see an example in the link I added.
The set is automatically created and takes the name of your object class, which is testEntity in your case. For example, based on your code, if you do not specify a collection in the #Document annotation a set named "testEntity" will automatically be created. I added the #Document(collection = "testEntitys") annotation and all I did was create two set. Once you insert your first record, run the "SHOW SETS" aql command and it will be there. So that's one way to do it.

How di I turn my class into an Entity in Room Persistence?

This is my first time using Room Persistence Library and I am having difficulties understanding the concept of entity.
So I have these two classes:
public class CapturedTime
{
#SerializedName("startTime")
#Expose
private Long startTime;
#SerializedName("endTime")
#Expose
private Long endTime;}
and
public class CapturedItem implements Parcelable {
private String serialNumber;
private CapturedTime firstCapturedTime;
private CapturedTime secondCapturedTime;}
I believe it's pretty straightforward for the CapturedTime class but I have no idea what I should do for the CapturedItem class. Can I just make the CapturedTime variables into columns or are there steps that I should do first?
First add dependency in buid.gradle file
dependencies {
def room_version = "2.1.0-rc01"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
}
After that use #Entity annotation to declare normal POJO class as entity in Room persistence library.
#Entity(tableName = "your_table_name")
public class CapturedTime{
#SerializedName("startTime")
#Expose
#ColumnInfo(name = "start_time")
private long startTime;
#SerializedName("endTime")
#Expose
#ColumnInfo(name = "end_time")
private long endTime;
}
#ColumnInfo used to declare column name in table, by default column name is variable name if you do't provide #ColumnInfo annotation
If you want to store custom object in room you use
#TypeConverters() annotation
In your case,
#TypeConverters(CapturedTime.class)
private CapturedTime firstCapturedTime;
For more information please visit this

Spring Boot 1.4: LocalDateTime mapped to varbinary instead of timestamp type

I am using Java 8, Spring Boot 1.4 and hsqldb.
I have an entity with java.time.LocalDateTime field.
When I check sql generated by hibernate, it is using varbinary as data type.
How do I make it use timestamp data type?
Update:
It does work when I add hibernate-java8 (5.1.0.Final) dependency.
But it does not work with hibernate-java8 (5.2.x versions). This might be because Java 8 support was added to hibernate-core 5.2 itself.
It works when hibernate-java8 (5.1.0.Final) dependency is added.
It DOES NOT work with hibernate-java8 (5.2.x versions).
This is because Java 8 support was added to hibernate-core 5.2 itself.
Another way would be to annotate your entity localDateTime_field with a converter.
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime localDateTime_field;
Here is how it goes:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Timestamp;
import java.time.LocalDateTime;
#Converter
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
#Override
public Timestamp convertToDatabaseColumn(LocalDateTime localDateTime) {
return localDateTime == null ? null : Timestamp.valueOf(localDateTime);
}
#Override
public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
return timestamp == null ? null : timestamp.toLocalDateTime();
}
}

Java 8 Date Time api in JPA

What is the best way how to integrate Java 8 Date Time api in jpa?
I have added converters:
#Converter(autoApply = true)
public class LocalDatePersistenceConverter implements AttributeConverter<LocalDate, Date> {
#Override
public Date convertToDatabaseColumn(LocalDate localDate) {
return Date.valueOf(localDate);
}
#Override
public LocalDate convertToEntityAttribute(Date date) {
return date.toLocalDate();
}
}
and
#Converter(autoApply = true)
public class LocalDateTimePersistenceConverter implements AttributeConverter<LocalDateTime, Timestamp> {
#Override
public Timestamp convertToDatabaseColumn(LocalDateTime entityValue) {
return Timestamp.valueOf(entityValue);
}
#Override
public LocalDateTime convertToEntityAttribute(Timestamp databaseValue) {
return databaseValue.toLocalDateTime();
}
}
Everything seems fine, but how should I use JPQL for querying? I am using Spring JPARepository, and goal is to select all entities where date is the same as date given, only difference is that it is saved in entity as LocalDateTime.
So:
public class Entity {
private LocalDateTime dateTime;
...
}
And:
#Query("select case when (count(e) > 0) then true else false end from Entity e where e.dateTime = :date")
public boolean check(#Param("date") LocalDate date);
When executing it just gives me exception, which is correct.
Caused by: java.lang.IllegalArgumentException: Parameter value [2014-01-01] did not match expected type [java.time.LocalDateTime (n/a)]
I have tried many ways, but it seems that none is working, is that even possible?
Hibernate has an extension library, hibernate-java8 I believe, which natively supports many of the time types.
You should use it before writing converters.
in hibernate 5.2 you won't need this additional library, it is part of core.
To query temporal fields you should use the #Temporal Anotation in the temporal fields, add the converters to persistence.xml and also be sure you are using the java.sql.Date,java.sql.Time or java.sql.Timestamp in the converters. (Sometimes i imported from the wrong package)
for example thats works for me:
#Temporal(TemporalType.TIMESTAMP)
#Convert(converter = InstantPersistenceConverter.class)
private Instant StartInstant;
#Temporal(TemporalType.TIME)
#Convert(converter = LocalTimePersistenceConverter.class)
private LocalTime StartTime;
and my Instant converter:
#Converter(autoApply = true)
public class InstantPersistenceConverter implements AttributeConverter <Instant,java.sql.Timestamp>{
#Override
public java.sql.Timestamp convertToDatabaseColumn(Instant entityValue) {
return java.sql.Timestamp.from(entityValue);
}
#Override
public Instant convertToEntityAttribute(java.sql.Timestamp databaseValue) {
return databaseValue.toInstant();
}
}
Did you add LocalDatePersistenceConverter and LocalDateTimePersistenceConverter in persistence.xml placed in 'class' element ?

Resources