I'm using Spring boot with spring data couchbase.
I've added two fields for createdDate and lastModifiedDate with #CreatedDate and #LastModifiedDate annotations in Movie Document.
lastModifiedDate works great but createdDate is always null.
#RequiredArgsConstructor
#NoArgsConstructor
#ToString
#EqualsAndHashCode
#Document
public class Movie {
#Id
#NonNull
#Getter
private String id;
#Getter
#Setter
#NonNull
private String title;
#Getter
#LastModifiedDate
private Date lastModifiedDate;
#Getter
#CreatedDate
private Date createdDate;
}
I've also added a configuration for #EnableCouchbaseAuditing:
#Configuration
#EnableCouchbaseAuditing
public class AuditConfiguration {
}
Movie Repository:
#N1qlPrimaryIndexed
#ViewIndexed(designDoc = "movie")
public interface MovieRepository extends CouchbaseRepository<Movie, String> {
Collection<Movie> findByTitle(String title);
Collection<Movie> findByTitleLike(String title);
Collection<Movie> findByTitleStartingWith(String title);
}
application.yml for reference:
spring:
couchbase:
bootstrap-hosts: localhost
bucket:
name: movie
data:
couchbase:
auto-index: true
As stated in the documentation, in order to distinguish between a creation and an update, spring-data-couchbase needs a #Version annotated attribute in the entity class
If anyone lands here ... I had an issue with the createdDate not being populated even though I followed the spring-data-couchbase documentation. I followed the process of creating immutable objects for my Document and Auditing. The cause was the field annotated with #CreatedDate was final (I used lombok #Value). I had to make it non-final (#NonFinal using Lombok) for it to finally work.
Related
I have a Spring Boot application with the following entities:
#Data
#Entity
#Table(name = "jokes")
#EqualsAndHashCode(callSuper = true)
public class Joke extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "content")
private String content;
}
and
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
private LocalDateTime createdAt;
#UpdateTimestamp
private LocalDateTime updatedAt;
}
My Controller:
#PostMapping("/jokes")
public Joke createJoke(#Valid #RequestBody Joke joke) {
return jokeRepository.save(joke);
}
The fields createdAt and updatedAt are automatically updated. I am using swagger and when I go on an end point which allows me to create a new resource, then swagger gives me the option of updating the fields createdAt and updatedAt at as well as shown below. The are not actually being updated, but I would like to not see them there. Anyone knows how I could do this?
If you want the fileds to be hidden only at the Swagger level, you can do it with the #Schema annotation of Swagger
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
#Schema(hidden = true) // One way to do it
private LocalDateTime createdAt;
#UpdateTimestamp
#Schema(accessMode = READ_ONLY) // Other way to do it
private LocalDateTime updatedAt;
}
The difference between the two of them is, hidden will remove the property from Schema component which will make it unavailable for both request and response payloads while accessMode will hide it only for request payloads and not show the access mode in the Schema component as mentioned in the documentation.
accessMode:
Allows to specify the access mode (AccessMode.READ_ONLY, READ_WRITE) AccessMode.READ_ONLY: value will not be written to during a request but may be returned during a response. AccessMode.WRITE_ONLY: value will only be written to during a request but not returned during a response. AccessMode.READ_WRITE: value will be written to during a request and returned during a response.
hidden:
Allows schema to be marked as hidden.
And if you want it to be ignored by the JSON parser that you're using, you'll need something like JsonIgnore if you're using Jackson as the parser.
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
#JsonIgnore // Jackson will ignore this field
private LocalDateTime createdAt;
#UpdateTimestamp
#JsonIgnore // this will also be ignored
private LocalDateTime updatedAt;
}
Preferably, using the #Indexed annotation, or some other declarative way, is it possible to inject a system property, preferably using SPeL.
I have tried the following but found expireAfterSeconds gives error because it wants an int:
#Data
#Document(collection = "#{#xyzUpdates.collectionName}")
public class UpdatesFromXyz {
#Id
#Field("resourceId")
private UUID resourceId;
#Indexed(expireAfterSeconds = "#{#xyzUpdates.maxRecords}")
private LocalDate updateDate;
}
and my properties class:
#ConfigurationProperties("xyz.updates")
#Getter
#Setter
#Component
public class XyzUpdates {
private String collectionName = "updatesFromXyz";
private int maxRecords;
}
Since SpringData MongoDB 2.2 you can use expireAfter which accepts numeric values followed by their unit of measure or a Spring template expression.
I have two data sources (MySQL and Elasticsearch) configured in a Spring Boot 2.0.2.RELEASE project and JpaAuditing enabled:
#Configuration
#EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
#EnableJpaRepositories("com.example.companies.repository")
#EnableElasticsearchRepositories("com.example.companies.repository.search")
public class DatabaseConfiguration {
}
And I have an entity which I store in both data sources:
#MappedSuperclass
#EntityListeners({AuditingEntityListener.class})
public abstract class AbstractAuditingEntity implements Serializable {
#CreatedBy
private String createdBy;
#CreatedDate
private Instant createdDate = Instant.now();
#LastModifiedBy
private String lastModifiedBy;
#LastModifiedDate
private Instant lastModifiedDate = Instant.now();
}
#Entity
#Table(name = "company")
#Document(indexName = "company")
public class Company extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
In Elasticsearch I need to have an exact copy of the entity in MySQL (including having the same createdDate and lastModifiedDate):
public Company save(Company company) {
// MySql repository
Company result = companyRepository.save(company);
// Elasticsearch repository
companySearchRepository.save(result);
return result;
}
On create, the entity has the same details in both repositories, but on update, lastModifiedDate receives a different value in the second repository.
Is there an easy way to enable auditing only for one of the two data sources?
Thank you.
I have an alert table which is transactional and an alert type table which is master. I would like to send out an email whenever an alert is added to the table, so I figured I would use PrePersist. However, in my email, I want to include some information that is included in the alert type table.
I have tried to add a reference to the AlertTypeRepository in the Alert class but I can't because my alert class is a #Table and alertTypeRepository is not a column.
Below is my Alert class
#Entity
#Table
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Alert {
#Id
#GeneratedValue
int id;
#Column
String name;
#Column
String alertTypeId;
#Column
String detailedMessage;
#Column
String status;
#Temporal(TemporalType.TIMESTAMP)
Date time;
}
Below is my AlertType class
#Entity
#Table
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class AlertType {
#Id
#GeneratedValue
int id;
#Column
String name;
#Column
String header;
#Column
String footer;
#Column
String summary;
#Column
String deliveryType;
#Column
Boolean active ;
#Column
String recipients;
}
I would like to have a PrePersist function inside of the Alert class. That allows me to access its corresponding header and footer from the AlertType class.
I figured out a solution so I hope this helps anyone facing a similar issue. Basically I had to create an EntityListener to the Alert class and then add the following class.
#Component
public class AlertListener {
static AlertTypeRepository alertTypeRepository;
#Autowired
public void init(AlertTypeRepository alertTypeRepository)
{
this.alertTypeRepository = alertTypeRepository;
}
#PrePersist
public void prePersist(Alert alert) {
List<AlertType> alertType= this.alertTypeRepository.findAll();
}
}
As I know the are two approaches to archive the purpose. Your alterType is not managed by Spring .
Define a JPA EntityListener and apply it on your entity class, which does not seem to interest you.
The second approach, annotated your entity with Spring #Configurable annotation:
#Configurable(preConstruction = true)
class AlterType{
#Inject YourRepository bean as normal.
}
To make it work. Firstly you have to add aspectj related jars into your project dependencies. Secondly you can choose load-time weaving or compile-time weaving to handling the injection for you class.
There is an example of aspectj compiler config in Maven can be used for compile-time weaving(note, just for aspectj compiler maven plugin config, I did not use #Configurable here.).
I use #Audited annotation in Spring to have auditing about my update, create etc. on my db.
But I obtain on my database, a date-time with 2 hour less than real time, for example, I created a object and the I saved it, I have as create date-time: 2014-08-04 12:0 but I created it at 14:00.
This is my Auditor class, that every class audited extend:
#SuppressWarnings("serial")
#MappedSuperclass
public abstract class AbstractAudit implements Auditable<String, Long>, Serializable {
#Version
private int version;
#JsonIgnore
#Column(updatable=false)
private String createdBy;
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
#DateTimeFormat(iso=ISO.DATE_TIME)
#JsonIgnore
#Column(updatable=false)
private DateTime createdDate;
#JsonIgnore
private String lastModifiedBy;
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
#DateTimeFormat(iso=ISO.DATE_TIME)
#JsonIgnore
private DateTime lastModifiedDate;
//getter and setter method
}
How can I fix it??
Have I add some configuration on my project or on my server (Tomcat 7) ?
Thanks
Try to set this property in your jpa provider settings:
<prop key="jadira.usertype.databaseZone">jvm</prop>
Hope this helps.
Regards