Spring data Cassandra #Indexed annotation - java

I was working on Spring data Cassandra While creating an entity I am giving the required annotations for fields but when I am giving #Indexed annotation for creating an secondary index in the Schema and I am not able to query on the indexed attribute with out giving Allow Filtering.Could some one please tell me how to create a Secondary Index using Spring data annotations in Cassandra
This is the sample cod that I am using creating a Sprind data Cassandra Entity.#Indexed annotation not creating a secondary index in Cassandra database
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.Indexed;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.cassandra.mapping.UserDefinedType;
import com.datastax.driver.core.DataType;
import com.suntecgroup.xelerate.platform.demo.config.SpringContainer;
import com.suntecgroup.xelerate.platform.demo.store.CustomerCassandraStore;
import com.suntecgroup.xelerate.platform.demo.store.impl.CustomerCassandraStoreImpl;
#Table(value="CustomerCassandra")
public class CustomerCassandra extends CassandraEntity<Integer> {
#PrimaryKey(value="cust_id")
private Integer custId;
#Indexed(value="name")
private String name;
#Indexed(value="email")
private String email;
#Column(value="domain")
private String domain;
#Column(value="category")
private String category;
#Column(value="created_at")
private Date createdAt;
#CassandraType(type=DataType.Name.LIST,typeArguments = { DataType.Name.UDT }, userTypeName = "address_demo_type")
#Column(value="addresses")
private List<Address> addresses;
#Override
public Integer getId() {
return custId;
}
#Override
public void setId(Integer id) {
this.custId = id;
}
public static CustomerCassandraStore getStore() {
return (CustomerCassandraStore) SpringContainer.getBean(CustomerCassandraStoreImpl.class);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(Address... addresses) {
LinkedList<Address> addressList = new LinkedList<>();
for(Address addr: addresses) {
addressList.add(addr);
}
setAddresses(addressList);
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
#UserDefinedType(value="address_demo_type")
public static class Address {
#CassandraType(type = DataType.Name.TEXT)
#Column(value="street_address")
private String streetAddress;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="city")
private String city;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="country")
private String country;
#CassandraType(type = DataType.Name.TEXT)
#Column(value="pincode")
private String pincode;
public String getStreetAddress() {
return streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getPincode() {
return pincode;
}
public void setPincode(String pincode) {
this.pincode = pincode;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result + ((country == null) ? 0 : country.hashCode());
result = prime * result + ((pincode == null) ? 0 : pincode.hashCode());
result = prime * result
+ ((streetAddress == null) ? 0 : streetAddress.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (city == null) {
if (other.city != null)
return false;
} else if (!city.equals(other.city))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
if (pincode == null) {
if (other.pincode != null)
return false;
} else if (!pincode.equals(other.pincode))
return false;
if (streetAddress == null) {
if (other.streetAddress != null)
return false;
} else if (!streetAddress.equals(other.streetAddress))
return false;
return true;
}}
}

It looks like some bug in spring-data-cassandra lib. I'm not able to create index through annotation as well.

I faced a similar issue while creating the schema during test execution (it's not clear how the OP creates the table based on the annotations).
My code was invoking CassandraAdminOperations.createTable() function and I quickly found out that createTable does not include indices, so any queries on the (supposedly) indexed columns were failing. My original code was just:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
}
In order to generate the indices based on the annotations, I had to modify my #Before method as:
#Autowired
private CassandraAdminOperations adminTemplate;
#Before
public void createTable() {
adminTemplate.createTable(true, CqlIdentifier.of(DATA_TABLE_NAME), User.class, new HashMap<>());
CassandraPersistentEntity<?> entity = adminTemplate.getConverter().getMappingContext().getRequiredPersistentEntity(User.class);
List<CreateIndexSpecification> indexSpecifications = adminTemplate.getConverter().getMappingContext().getCreateIndexSpecificationsFor(entity);
indexSpecifications.forEach(is -> adminTemplate.getCqlOperations().execute((CreateIndexCqlGenerator.toCql(is))));
}

Table tableAnno=AnnotationUtils.getAnnotation(MessagePO.class, Table.class);
String tableName=tableAnno.value();
log.info("initial table{}",tableName);
/**
* create table
*/
adminTemplate.createTable(true, CqlIdentifier.fromCql(tableName), MessagePO.class, null);
Field[] fields = MessagePO.class.getDeclaredFields();
/**
* create index
*/
CqlOperations cqlOperations=adminTemplate.getCqlOperations();
Arrays.stream(fields).forEach(field -> {
Indexed indexed = AnnotationUtils.getAnnotation(field, Indexed.class);
Column column = AnnotationUtils.getAnnotation(field, Column.class);
if (indexed != null && column != null) {
String indexVal = indexed.value();
String indexSql=String.format("CREATE INDEX %s on %s(%s)",indexVal,tableName,column.value());
cqlOperations.execute(String.format("DROP INDEX if EXISTS %s",indexVal));
cqlOperations.execute(indexSql);
log.info("create index {}",indexSql);
}
});
this is my initial index code, it's work well

Related

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crudRepository'

I work with a Spring boot project and I have the following entity class provided,
#Entity
public class User {
// form:hidden - hidden value
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
// form:input - textbox
#Column(name = "name", columnDefinition = "VARCHAR(30)", nullable = false)
String name;
// form:input - textbox
#Column(name = "email", columnDefinition = "VARCHAR(50)", nullable = false)
String email;
// form:textarea - textarea
#Column(name = "address", columnDefinition = "VARCHAR(255)", nullable = true)
String address;
// form:input - password
#Column(name = "password", columnDefinition = "VARCHAR(20)", nullable = false)
String password;
// form:input - password
String confirmPassword;
// form:checkbox - single checkbox
#Column(name = "newsletter", nullable = true)
boolean newsletter;
// form:checkboxes - multiple checkboxes
// #Column(columnDefinition = "VARCHAR(500)", nullable = false)
#ElementCollection
List<String> framework;
// form:radiobutton - radio button
#Column(name = "sex", columnDefinition = "VARCHAR(1)", nullable = true)
String sex;
// form:radiobuttons - radio button
#Column(name = "number", nullable = true)
Integer number;
// form:select - form:option - dropdown - single select
#Column(name = "", columnDefinition = "VARCHAR(10)", nullable = true)
String country;
// form:select - multiple=true - dropdown - multiple select
// #Column(columnDefinition = "VARCHAR(500)", nullable = true)
#ElementCollection
List<String> skill;
//Check if this is for New of Update
public boolean isNew() {
return (this.id == null);
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public boolean isNewsletter() {
return newsletter;
}
public void setNewsletter(boolean newsletter) {
this.newsletter = newsletter;
}
public List<String> getFramework() {
return framework;
}
public void setFramework(List<String> framework) {
this.framework = framework;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public List<String> getSkill() {
return skill;
}
public void setSkill(List<String> skill) {
this.skill = skill;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (isNewsletter() != user.isNewsletter()) return false;
if (!getId().equals(user.getId())) return false;
if (!getName().equals(user.getName())) return false;
if (!getEmail().equals(user.getEmail())) return false;
if (getAddress() != null ? !getAddress().equals(user.getAddress()) : user.getAddress() != null) return false;
if (!getPassword().equals(user.getPassword())) return false;
if (getConfirmPassword() != null ? !getConfirmPassword().equals(user.getConfirmPassword()) : user.getConfirmPassword() != null)
return false;
if (!getFramework().equals(user.getFramework())) return false;
if (getSex() != null ? !getSex().equals(user.getSex()) : user.getSex() != null) return false;
if (getNumber() != null ? !getNumber().equals(user.getNumber()) : user.getNumber() != null) return false;
if (getCountry() != null ? !getCountry().equals(user.getCountry()) : user.getCountry() != null) return false;
return getSkill() != null ? getSkill().equals(user.getSkill()) : user.getSkill() == null;
}
#Override
public int hashCode() {
int result = getId().hashCode();
result = 31 * result + getName().hashCode();
result = 31 * result + getEmail().hashCode();
result = 31 * result + (getAddress() != null ? getAddress().hashCode() : 0);
result = 31 * result + getPassword().hashCode();
result = 31 * result + (getConfirmPassword() != null ? getConfirmPassword().hashCode() : 0);
result = 31 * result + (isNewsletter() ? 1 : 0);
result = 31 * result + getFramework().hashCode();
result = 31 * result + (getSex() != null ? getSex().hashCode() : 0);
result = 31 * result + (getNumber() != null ? getNumber().hashCode() : 0);
result = 31 * result + (getCountry() != null ? getCountry().hashCode() : 0);
result = 31 * result + (getSkill() != null ? getSkill().hashCode() : 0);
return result;
}
}
I would like to write some customized operations and tried to define the interfaces in that respect. The repository interfaces are provided below,
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);
Iterable<T> findAll();
Long count();
void delete(T entity);
boolean exists(ID primaryKey);
// … more functionality omitted.
}
This interface extends the previously provided interface,
#Repository
public interface IUserRepository extends CrudRepository<User, Long>{
}
While I compile the program, I get the following error,
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'crudRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class java.lang.Object
What is the issue here?
Updated
The Spring Boot Application class is,
#SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebApplication.class, args);
}
}
Add #NoRepositoryBean to your CrudRepository. This will allow auto-configuration to still occur without having to manually set the component scanning base packages.
The interface org.springframework.data.repository.Repository is a marker for an actual spring data repository. Since your CrudRepository extends Repository spring is trying to initialize a Spring managed repository named crudRepository for T (which essentially tranlates to Object). Since Object isn't managed by Hibernate it fails validation on startup and crashes.
#NoRepositoryBean will tell Spring to not generate a backing repository for a particular class that implements Repository.

PK of #ManyToOne relation not inserted

I have an application (Spring 4 MVC+Hibernate 4+MySQL+Maven integration example using annotations) , integrating Spring with Hibernate using annotation based configuration.
I have this domain object:
#Entity
#Table(name="t_device")
public class Device {
enum Type {
IOS,
ANDROID
}
public Device() {
super();
}
public Device(String key) {
super();
this.key = key;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty
#Size(min=1, max=50)
#Column(name = "device_key", unique=true, nullable = false)
private String key;
#Column(name = "device_desc")
private String desc;
#Enumerated(EnumType.STRING)
#Column(name = "device_type")
private Type type;
#OneToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "application_id",
referencedColumnName = "id")
private Application application;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Application getApplication() {
return application;
}
public void setApplication(Application application) {
this.application = application;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((desc == null) ? 0 : desc.hashCode());
result = prime * result + id;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Device other = (Device) obj;
if (desc == null) {
if (other.desc != null)
return false;
} else if (!desc.equals(other.desc))
return false;
if (id != other.id)
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
#Override
public String toString() {
return "Device [id=" + id + ", key=" + key + ", desc=" + desc + "]";
}
}
That is linked to this other one:
#Entity
#Table(name="t_device_event")
public class DeviceEvent {
public class Coordinates {
#Column(name = "device_lat")
private Double lat;
#Column(name = "device_lng")
private Double lng;
public Coordinates(Double lat, Double lng) {
super();
this.lat = lat;
this.lng = lng;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLng() {
return lng;
}
public void setLng(Double lng) {
this.lng = lng;
}
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
private Device device;
private Long received;
private String message;
#Transient
private Coordinates coordinates;
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public Long getReceived() {
return received;
}
public void setReceived(Long received) {
this.received = received;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public DeviceEvent(Device device) {
super();
this.device = device;
}
}
and this piece of code in the controller:
Device device = deviceService.findByKey("AS3989E506");
DeviceEvent deviceEvent = new DeviceEvent(device);
deviceEvent.setCoordinates(deviceEvent.new Coordinates(Double.MIN_VALUE, Double.MAX_VALUE));
deviceEvent.setMessage("message");
deviceEvent.setReceived(new Date().getTime());
deviceEventService.save(deviceEvent);
and the hibernate console:
Hibernate:
select
this_.id as id1_1_1_,
this_.application_id as applicat5_1_1_,
this_.device_desc as device_d2_1_1_,
this_.device_key as device_k3_1_1_,
this_.device_type as device_t4_1_1_,
applicatio2_.id as id1_0_0_,
applicatio2_.application_desc as applicat2_0_0_,
applicatio2_.application_key as applicat3_0_0_
from
t_device this_
left outer join
t_application applicatio2_
on this_.application_id=applicatio2_.id
where
this_.device_key=?
Hibernate:
insert
into
t_device_event
(device_id, message, received)
values
(?, ?, ?)
Hibernate:
select
this_.id as id1_1_1_,
this_.application_id as applicat5_1_1_,
this_.device_desc as device_d2_1_1_,
this_.device_key as device_k3_1_1_,
this_.device_type as device_t4_1_1_,
applicatio2_.id as id1_0_0_,
applicatio2_.application_desc as applicat2_0_0_,
applicatio2_.application_key as applicat3_0_0_
from
t_device this_
left outer join
t_application applicatio2_
on this_.application_id=applicatio2_.id
Here the services:
#Service("deviceEventService")
#Transactional
public class DeviceEventServiceImpl implements DeviceEventService {
#Autowired
private DeviceEventDao dao;
public void save(DeviceEvent deviceEvent) {
dao.save(deviceEvent);
}
}
the other:
#Service("deviceService")
#Transactional
public class DeviceServiceImpl implements DeviceService {
#Autowired
private DeviceDao dao;
public Device findById(int id) {
return dao.findById(id);
}
public void save(Device device) {
dao.save(device);
}
public void update(Device device) {
// TODO Auto-generated method stub
}
public void delete(Device device) {
// TODO Auto-generated method stub
}
public List<Device> findAll() {
return dao.findAll();
}
public Device findByKey(String key) {
return dao.findByKey(key);
}
public boolean isDeviceKeyUnique(Integer id, String key) {
Device device = findByKey(key);
return ( device == null || ((id != null) && (device.getId() == id)));
}
public void deleteByKey(String key) {
dao.deleteByKey (key);
}
}
But the field device_id of the table t_device_event is null !
May be #JoinColumn annotation will help you
#ManyToOne
#JoinColumn(name="device_id")
private Device device;

JPA cannot fill entries in join table

I'm trying to map a bidirectional ManyToMany relationship between the class Problem and the class Domain. Therefore the persistency unit creates a join table in the database, but it seems no entry pops up in the database.
Here's some code:
The class Problem
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Problem implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private User user;
private String description;
private int maxprice;
private int priority;
private Solution solution;
private Location location;
private List<Domain> domains;
#Id
//#GeneratedValue(strategy = GenerationType.AUTO)
#SequenceGenerator(name="User_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Problem_Seq")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne
//#JoinColumn(name="user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getMaxPrice() {
return maxprice;
}
public void setMaxPrice(int maxprice) {
this.maxprice = maxprice;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="solution_id")
public Solution getSolution() {
return solution;
}
public void setSolution(Solution solution) {
this.solution = solution;
}
#ManyToOne
#JoinColumn(name="location_id")
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
#ManyToMany
#JoinTable(name="problem_domain",
joinColumns={#JoinColumn(name="problem_id", referencedColumnName="ID")},
inverseJoinColumns={#JoinColumn(name="domain_id", referencedColumnName="ID")})
public List<Domain> getDomains() {
return domains;
}
public void setDomains(List<Domain> domains) {
this.domains = domains;
}
public void addDomain(Domain domain){
//this.domains.add(domain); //Throws NullpointerException om een of andere reden.
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Problem)) {
return false;
}
Problem other = (Problem) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "domain.Problem[ id=" + id + " ]";
}
}
The class Domain
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package domain;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
import javax.xml.bind.annotation.XmlRootElement;
#Entity
#XmlRootElement
public class Domain implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private List<Problem> problems;
private List<Domain> subDomains;
private Domain superDomain;
#Id
#SequenceGenerator(name="Dom_Seq", allocationSize=25)
#GeneratedValue(strategy=SEQUENCE, generator="Dom_Seq")
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;
}
#ManyToMany(mappedBy = "domains")
public List<Problem> getProblems() {
return problems;
}
public void setProblems(List<Problem> problems) {
this.problems = problems;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="superdomain_id")
public List<Domain> getSubDomains() {
return subDomains;
}
public void setSubDomains(List<Domain> subDomains) {
this.subDomains = subDomains;
}
public Domain getSuperDomain() {
return superDomain;
}
public void setSuperDomain(Domain superDomain) {
this.superDomain = superDomain;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Domain)) {
return false;
}
Domain other = (Domain) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "domain.Domain[ id=" + id + " ]";
}
}
the code where we add a problem and a domain to the database
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
problemFacade.create(problem);
problem.addDomain(domain);
problemFacade.edit(problem);
and a little visual explanation of the DB
Do you try to save List of domain to problem?
Example of code:
Problem problem = new Problem();
Domain domain = new Domain();
domain.setName(domainString);
domainFacade.create(domain);
List<Domain> domains = new ArrayList<Domain>();
domains.add(domain);
problem.setDomains(domains);
problemFacade.create(problem);
As #Neil Stockton and others said, the answer to my problem was that I had to have an addMethod that simply added the object to the list.

Found two representations of same collection hibernate exception

I have a Spring MVC application that handle Users and Structures that can hosts one or more User.
I'm using Hibernate for the persistence and I'm having some issues with the One-To-Many relation between User and Structure.
This is my User model:
#Entity
#Table(name="USERS")
public class User extends DatabaseEntity {
#Id #GeneratedValue
private Long id = 0L;
#Column
#NotEmpty
private String firstName;
#Column
private String lastName;
#Column
private Date birthDate;
#Column
private String nation;
#Column
private String town;
#Column
private String idNumber;
#Column(unique = true)
private String email;
#Column String resetPasswordToken = "";
#Column
private String password;
#Column
private String avatarUrl;
#Column #Enumerated(EnumType.STRING)
private Role role;
#ManyToOne
#JoinColumn(name = "STRUCTURE_ID")
#Cascade({CascadeType.DETACH})
private Structure structure;
public enum Role {
ADMINISTRATOR,
SPECIALIST,
PATIENT,
DOCTOR,
CARE_GIVER
}
public User() {
birthDate = new Date();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public Set<Group> getGroups() {
return null;
}
public void setGroups(Set<Group> groups) {
}
public Set<Group> getCreatedGroups() {
return null;
}
public void setCreatedGroups(Set<Group> createdGroups) {
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<HangoutUser> getHangoutUsers() {
return null;
}
public void setHangoutUsers(Set<HangoutUser> hangoutUsers) {
}
public String getResetPasswordToken() {
return resetPasswordToken;
}
public void setResetPasswordToken(String resetPasswordToken) {
this.resetPasswordToken = resetPasswordToken;
}
public Group getStructure() {
return structure;
}
public void setStructure(Structure structure) {
this.structure = structure;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (!email.equals(user.email)) return false;
if (!id.equals(user.id)) return false;
return true;
}
#Override
public int hashCode() {
Long res = id;
if(id == null)
res = 0L;
int result = res.hashCode();
result = 31 * result + email.hashCode();
return result;
}
}
And this is my Structure model:
#Entity
#Table(name = "STRUCTURES")
public class Structure extends DatabaseEntity {
#Id #GeneratedValue
Long id = 0L;
#Column
String name;
#Column
String address;
#Column
String city;
#Column
String state;
#OneToMany(mappedBy = "structure", fetch = FetchType.EAGER)
#Cascade({CascadeType.DELETE})
Set<User> users = new HashSet<User>();
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;
}
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
public Set<User> getUsers()
{
return this.users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
My issue is that when I try to find all the Users with the value STRUCTURE_ID evaluated, I get an Hibernate Exception, like this:
org.springframework.orm.hibernate3.HibernateSystemException: Found two representations of same collection: it.amtservices.livinglab.model.Group.users; nested exception is org.hibernate.HibernateException: Found two representations of same collection: it.amtservices.livinglab.model.Structure.users
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:690) ...
What should I do to solve this problem? I have already tried many ways but nothing solved.
I paste the abstract repository implementation for the UsersRepository and StructureRepository:
#Transactional
public abstract class AbstractRepository<Model extends DatabaseEntity>
{
Logger logger = Logger.getLogger(this.getClass().getSimpleName());
#PersistenceContext
EntityManager em;
protected Class<Model> ModelClass;
protected List<Model> findBy(String parameterName, Object parameterValue)
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where t." + parameterName + " = :" + parameterName);
q.setParameter(parameterName, parameterValue);
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected List<Model> findBy(Map<String, Object> parameters)
{
String whereClause = "";
for (String key : parameters.keySet())
{
if (!whereClause.equals("")) whereClause += " and ";
whereClause += "t." + key + " = :" + key;
}
Query q = null;
try
{
q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t where " + whereClause);
}
catch (Exception e)
{
e.printStackTrace();
}
for (String key : parameters.keySet())
{
q.setParameter(key, parameters.get(key));
}
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
protected Model findOneBy(String parameterName, Object parameterValue)
{
List<Model> results = findBy(parameterName, parameterValue);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
protected Model findOneBy(Map<String, Object> parameters)
{
List<Model> results = findBy(parameters);
if (results != null && results.size() > 0) return results.get(0);
return null;
}
public Model findOne(Long id)
{
return findOneBy("id", id);
}
public List<Model> findAll()
{
Query q = em.createQuery("select t from " + ModelClass.getSimpleName() + " t");
List<Model> results = null;
try
{
results = q.getResultList();
}
catch (Exception e)
{
return null;
}
return results;
}
public boolean save(Model model)
{
try
{
Model newModel = em.merge(model);
if (model.getId() == 0L) model.setId(newModel.getId());
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
return false;
}
return true;
}
public void save(List<Model> models)
{
for (Model model : models)
{
save(model);
}
}
public void delete(Model model)
{
delete(model.getId());
}
public void delete(Long id)
{
beforeDelete(findOne(id));
try
{
Query q = em.createQuery("delete from " + ModelClass.getSimpleName() + " t where t.id = :id").setParameter("id", id);
q.executeUpdate();
}
catch (Exception e)
{
logger.error(ModelClass.getSimpleName() + "Repository: " + e.getMessage());
}
}
public void delete(Collection<Model> models)
{
for (Model model : models)
{
delete(model.getId());
}
}
public void deleteAll()
{
for (Model model : findAll())
{
delete(model);
}
}
public abstract void beforeDelete(Model model);
public List<Model> find(List<Long> ids)
{
List<Model> models = new ArrayList<Model>();
for (Long id : ids)
{
Model model = findOne(id);
if (model != null) models.add(model);
}
return models;
}
}
Thank you!

Objectify 4 - Fields are not persisted

Using Objectify 4, name and price fields are not persisted when I save a MenuItem object.
Only Key, WriteOps and ID/Name are persisted in the debugging datastore.
#Entity
public class MenuItem extends BaseEntity {
private String name;
private double price;
public MenuItem() {
}
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
Where BaseEntity is:
public abstract class BaseEntity implements Dto {
private static final long serialVersionUID = 8400346403708831769L;
#Id
protected Long id;
protected BaseEntity() {
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
public Long getId() {
return id;
}
public void setId(#Nullable Long id) {
this.id = id;
}
public boolean isSaved() {
return (id != null);
}
}
and Dto is:
public interface Dto extends Serializable {
}
Any ideas? Thanks!
As stated on the Objectify mailing list, it may just be your viewing of the datastore that is missing this information.
Can you show some test code to save this data then retrieve it and print out the results rather than using the datastore viewer? I'd expect:
MenuItem toSave = new MenuItem("test", 6.3);
toSave.setId(1);
ofy().save().entity(toSave).now();
ofy().clear(); //Make sure we're not just looking at the current session.
MenuItem loaded = ofy().load().type(MenuItem.class).id(1).get();
assertEquals(loaded.getName(), "test");
assertEquals(loaded.getPrice(), 6.3);

Categories