Sprint Date Rest successful, but no data - spring

Entity
#Data
#Accessors(chain = true, fluent = true)
#Entity
#Table(name = "T_NOTE")
#Access(AccessType.FIELD)
public class Note implements Serializable
{
#Id
#GeneratedValue
private Long id;
private Date date;
#Column(length = 2000)
private String content;
private String title;
private String weather;
}
Repository
#RepositoryRestResource(collectionResourceRel = "note", path = "note")
public interface NoteRepository extends AbstractRepository<Note, Long>
{
}
GET http://localhost:8080/note/2
{
"_links": {
"self": {
"href": "http://localhost:8080/note/2"
}
}
}
No entity field data, why?
EIDT
After I add standard setter/getter, everything is ok now.
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getWeather()
{
return weather;
}
public void setWeather(String weather)
{
this.weather = weather;
}
Is this cause by jackson mapper ? How can I use fluent API with this ?Why not just use reflection to generate JSON ?
EDIT
What I need is this configuration
#Configuration
#Import(RepositoryRestMvcConfiguration.class)
public class ShoweaRestMvcConfiguration extends RepositoryRestMvcConfiguration
{
#Override
protected void configureJacksonObjectMapper(ObjectMapper mapper)
{
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
}
}
Caused by this

#Accessors is probably stepping over the #Data annotation, and with fluent = true it generates getters with the same name as the field, like id() and date() (#Accessor documentation). That's why Spring doesn't see any of the fields.
I think you can safely remove both #Accessors and #Access, since #Access's takes the default value from id (if you annotated the field, it will be FIELD, if you annotated the getter, it will be PROPERTY).

Related

Why the class attributes in the quarku panache example are PUBLIC instead of PRIVATE

Referring to the getting started link below
https://quarkus.io/guides/hibernate-orm-panache
The example uses a Entity class with public attributes.
class Person{
public String name;
}
and used as
person.name = "Synd";
so is it simply a lazy example (!! in official doc ? ) or it means something else.
According to the documentation, it might be related to a single difference (extending PanacheEntityBase)
If you don’t want to bother defining getters/setters for your entities, you can make them extend PanacheEntityBase and Quarkus will generate them for you. You can even extend PanacheEntity and take advantage of the default ID it provides.
Therefore they are making them Public for Quarkus to generate getters/setters for you automatically.
#Entity
public class Person extends PanacheEntity {
public String name;
public LocalDate birth;
public Status status;
public static Person findByName(String name){
return find("name", name).firstResult();
}
public static List<Person> findAlive(){
return list("status", Status.Alive);
}
public static void deleteStefs(){
delete("name", "Stef");
}
}
vs
#Entity
public class Person {
#Id #GeneratedValue private Long id;
private String name;
private LocalDate birth;
private Status status;
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getBirth() {
return birth;
}
public void setBirth(LocalDate birth) {
this.birth = birth;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
}

null values inserted while auditing

My AuditListener
public class EmployeeAuditListeners {
#PrePersist
public void prePersist(Employee employee){
perform(employee,Action.INSERTED);
}
#PreUpdate
public void preUpdate(Employee employee){
perform(employee,Action.UPDATED);
}
#PreRemove
public void preRemove(Employee employee){
perform(employee,Action.DELETED);
}
#Transactional
public void perform(Employee emp, Action action){
EntityManager em = BeanUtil.getBean(EntityManager.class);
CommonLogs commonLogs = new CommonLogs();
commonLogs.setQuery("new query");
em.persist(commonLogs);
}
}
and My Auditable.class
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {
#CreatedBy
protected U createdBy;
#CreatedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date createdDate;
#LastModifiedBy
protected U lastModifiedBy;
#LastModifiedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date lastModifiedDate;
}
My CommonLogs.class
#Entity
#EntityListeners(AuditingEntityListener.class)
public class CommonLogs extends Auditable<String> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String query;
public CommonLogs() {
}
public CommonLogs(String query) {
this.query = query;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
My Employee.java class
#Entity
#EntityListeners(EmployeeAuditListeners.class)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
and I have a simple Rest Controller
#RestController
#RequestMapping("/api")
public class EmployeeController {
#Autowired
private EmployeeRepository employeeRepository;
#PostMapping("/employees")
public Employee createEmployee(#RequestBody Employee employee){
return employeeRepository.save(employee);
}
}
I want to log it on my table (common_logs) every time i perform some crud operations on my Employee Entity.
the above given example is working to some extent as it successfully stores employee and invokes EmployeeAuditListeners.
but now while saving CommongLog entity i expect it's parent class Auditable to automatically insert createdBy, createdDate etc. for now only query and id is inserted on common_logs table and remaining columns are null.
You can review the documentation for Auditing in here.
To enable the automatic Auditing, you must add the annotation #EnableJpaAuditing in your Application class:
#SpringBootApplication
#EnableJpaAuditing
class Application {
static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
}
If you want the fields #CreatedBy and #LastModifiedBy too, you will also need to implement the AuditorAware<T> interface. For example:
class SpringSecurityAuditorAware implements AuditorAware<User> {
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}

Spring JPARepository Update a field

I have a simple Model in Java called Member with fields - ID (Primary Key), Name (String), Position (String)
I want to expose an POST endpoint to update fields of a member. This method can accept payload like this
{ "id":1,"name":"Prateek"}
or
{ "id":1,"position":"Head of HR"}
and based on the payload received, I update only that particular field. How can I achieve that with JPARepository?
My repository interface is basic -
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository("memberRepository")
public interface MemberRepository extends JpaRepository<Member, Integer>{
}
My Member model -
#Entity
#Table(name="members")
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="member_id")
private Integer id;
#Column(name="member_name")
#NotNull
private String name;
#Column(name="member_joining_date")
#NotNull
private Date joiningDate = new Date();
#Enumerated(EnumType.STRING)
#Column(name="member_type",columnDefinition="varchar(255) default 'ORDINARY_MEMBER'")
private MemberType memberType = MemberType.ORDINARY_MEMBER;
public Member(Integer id, String name, Date joiningDate) {
super();
this.id = id;
this.name = name;
this.joiningDate = joiningDate;
this.memberType = MemberType.ORDINARY_MEMBER;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}
public MemberType getMemberType() {
return memberType;
}
public void setMemberType(MemberType memberType) {
this.memberType = memberType;
}
public Member(String name) {
this.memberType = MemberType.ORDINARY_MEMBER;
this.joiningDate = new Date();
this.name = name;
}
public Member() {
}
}
Something like this should do the trick
public class MemberService {
#Autowired
MemberRepository memberRepository;
public Member updateMember(Member memberFromRest) {
Member memberFromDb = memberRepository.findById(memberFromRest.getid());
//check if memberFromRest has name or position and update that to memberFromDb
memberRepository.save(memberFromDb);
}
}

Repeated column in mapping for entity: Shipper column: SHIPPER_ID (should be mapped with insert="false"

I have been going around in circles with this error and not sure why I am getting this.
Here is the mapping of Shipper class
#Entity
#Table(schema="SALONBOOKS",name="SHIPPER")
#AttributeOverride(name="id", column=#Column(name="SHIPPER_ID"))
public class Shipper extends SalonObject {
private static final long serialVersionUID = 1L;
private ShipperType name;//ShipperType.WALKIN;
#Column(name="SHIPPER_NAME")
#Enumerated(EnumType.STRING)
public ShipperType getName() {
return name;
}
public void setName(ShipperType name) {
this.name = name;
}
#Override
public Long getId(){
return id;
}
}
Here is Order class which references Shipper
#Entity
#Table(schema="SALONBOOKS",name="ORDER")
#AttributeOverride(name="id", column=#Column(name="ORDER_ID"))
public class Order extends SalonObject {
private static final long serialVersionUID = 1L;
private BigDecimal total= new BigDecimal(0.0);
private int numOfItems=0;
private BigDecimal tax= new BigDecimal(0.0);;
private String currency="USD";
private BigDecimal subTotal= new BigDecimal(0.0);
private PaymentMethod paymentMethod;
private Shipper shipper;
private OrderStatusType status;
private Appointment appointment ;
private Person person;
#Column(name="TOTAL")
public BigDecimal getTotal() {
return total;
}
public void setTotal(BigDecimal total) {
this.total = total;
}
#Column(name="NUM_OF_ITEMS")
public int getNumOfItems() {
return numOfItems;
}
public void setNumOfItems(int numOfItems) {
this.numOfItems = numOfItems;
}
#Column(name="TAX")
public BigDecimal getTax() {
return tax;
}
public void setTax(BigDecimal tax) {
this.tax = tax;
}
#Column(name="CURRENCY")
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
#Column(name="SUBTOTAL")
public BigDecimal getSubTotal() {
return subTotal;
}
public void setSubTotal(BigDecimal subTotal) {
this.subTotal = subTotal;
}
#ManyToOne
#JoinColumn(name="PAYMENT_METHOD_ID", insertable=false,updatable=false)
public PaymentMethod getPaymentMethod() {
return paymentMethod;
}
public void setPaymentMethod(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
#ManyToOne
#JoinColumn(name="SHIPPER_ID", insertable=false,updatable=false)
public Shipper getShipper() {
return shipper;
}
public void setShipper(Shipper shipVia) {
this.shipper = shipVia;
}
#Column(name="STATUS")
#Enumerated(EnumType.STRING)
public OrderStatusType getStatus() {
return status;
}
public void setStatus(OrderStatusType status) {
this.status = status;
}
#ManyToOne
#JoinColumn(name="APPOINTMENT_ID", insertable=false,updatable=false)
public Appointment getAppointment() {
return appointment;
}
public void setAppointment(Appointment appointment) {
this.appointment = appointment;
}
#ManyToOne
#JoinColumn(name="PERSON_ID", insertable=false,updatable=false)
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
#Override
public Long getId(){
return id;
}
}
each of these extends:
#MappedSuperclass
public abstract class SalonObject implements Entity, Serializable {
private static final long serialVersionUID = 1L;
protected Long id;
protected DateTime createDate;
protected DateTime updateDate;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof SalonObject
&& obj !=null){
return ObjectUtils.equals(this.id, ((SalonObject) obj).getId()) ;
}
return false;
}
#Column(name="CREATE_DATE")
public DateTime getCreateDate() {
return createDate;
}
public void setCreateDate(DateTime dateTime) {
this.createDate = dateTime;
}
#Column(name="UPDATE_DATE")
public DateTime getUpdateDate() {
return updateDate;
}
public void setUpdateDate(DateTime updateDate) {
this.updateDate = updateDate;
}
}
The stackTrace is ::
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: salonbooks.model.Shipper column: SHIPPER_ID (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:731)
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:753)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1358)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:343)
at salonbooks.core.HibernateConfiguration.sessionFactory(HibernateConfiguration.java:109)
removing the following method from Shipper and from Order worked to resolve this error
#Override
public Long getId(){
return id;
}
Because you are using property access, by overriding the base method (containing the mapping configuration) you will replace your base method mapping configuration with no config at all.
Using field access wouldn't have caused this issue, but the override would have been useless anyway. The id field should have private access too, so this method wouldn't compile if you change the access modifier.

Spring JPA repository query can't find ID property

I need a spring repository method that lets me get a list of Scene entities using a list of id's. When I try to refer to the Scene Id I get an error, saying it can't find the property called IdScene. I am using a custom query to do this. Is there something wrong with my query?
My Entity is
public class Scene implements Serializable
{
private long id_scene;
private Media media;
private int sceneNumber;
private int version;
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_scene")
public long getIdScene() {
return id_scene;
}
public void setIdScene(long id_scene) {
this.id_scene = id_scene;
}
#ManyToOne
#JoinColumn(name = "id_media")
public Media getMedia() {
return this.media;
}
public void setMedia(Media media) {
this.media = media;
}
private List<Thumbnail> thumbnails = new ArrayList<Thumbnail>();
#OneToMany(mappedBy = "scene", cascade=CascadeType.ALL,
orphanRemoval=true)
#LazyCollection(LazyCollectionOption.FALSE)
public List<Thumbnail> getThumbnails() {
return this.thumbnails;
}
public void setThumbnails(List<Thumbnail> thumbnails) {
this.thumbnails = thumbnails;
}
public void addThumbnail(Thumbnail thumbnail) {
thumbnail.setScene(this);
this.thumbnails.add(thumbnail);
}
private Property property;
#OneToOne(mappedBy="scene", cascade=CascadeType.ALL,
orphanRemoval=true)
#LazyCollection(LazyCollectionOption.FALSE)
public Property getProperty() {
return property;
}
public void setProperty(Property property) {
this.property = property;
}
public void addProperty(Property property) {
property.setScene(this);
this.property = property;
}
#Column(name = "sceneNumber")
public int getSceneNumber() {
return sceneNumber;
}
public void setSceneNumber(int sceneNumber) {
this.sceneNumber = sceneNumber;
}
#Column(name = "version")
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
My repository:
public interface SceneRepository extends JpaRepository<Scene, Long> {
public final static String FIND_BY_ID_LIST = "SELECT s"
+ " FROM Scene s WHERE s.IdScene IN (:id)";
#Query(FIND_BY_ID_LIST)
public List<Scene> findByIdScene(#Param("id") List<Long> id);//, Pageable page);
}
try:
"SELECT s FROM Scene s WHERE s.idScene IN (:id)"
note lower case 'i' in 'idScene'"
This is because of the Java Bean naming convention, a property defined as:
public String getWibble() { return wibble; }
public void setWibble(String value) { wibble = value; }
defines wibble and not Wibble

Resources