I'm trying to write some code that determines if a customer has certain feature. I have this method for that:
#Transactional(readOnly = true)
public boolean customerHasFeature(String customerId, String feature) {
Customer customer = customerDAO.findByCid(customerId);
if(customer != null) {
return customer.hasFeatureNamed(feature);
}
return false;
}
The customerDAO method is here
#Transactional(readOnly = true)
public Customer findByCid(String cid) {
List<Customer> customers = findByCriteriaImpl(Restrictions.eq("cid", cid));
if(customers.size() > 0)
return customers.get(0);
return null;
}
In customerHasFeature after I retrieve the customer it doesn't load the features and I get the error
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.socialware.model.Customer.features, no session or session was closed
When debugging findbyCid, I can see the features loaded after the criteria retrieves the customer, but when returned customer gets to customerHasFeature, it has an error.
I tried adding
Hibernate.initialize(customer.getFeatures());
after I call the customerDAO in customerHasFeature method but then I get
org.hibernate.HibernateException: collection is not associated with any session
I'm using hibernate 3,I appreciate any help or guides.
EDIT
Here's the findByCriteriaImpl method.
List<T> findByCriteriaImpl(Criterion... criterion) {
Criteria crit = createCriteria(getPersistentClass());
if (criterion != null) {
for (Criterion c : criterion) {
crit.add(c);
}
}
long startTime = System.currentTimeMillis();
List<T> toReturn = crit.list();
reportQueryTimeForMonitoring(System.currentTimeMillis() - startTime, "findByCriteriaImpl", "for criteria " + crit);
return toReturn;
}
And the Customer class
public class Customer implements Serializable{
private static final long serialVersionUID = -1L;
#Field(index=Index.UN_TOKENIZED)
private long customerId;
private String cid;
//#Field
private String name;
private Set<Feature> features;
private boolean deleted = false;
private String randomKey;
public Customer() {
}
#Override
public String toString() {
return new StringBuilder()
.append("Customer{")
.append(customerId).append(", ")
.append(cid).append(", ")
.append(name).append(", ")
.append(deleted)
.append("}").toString();
}
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
Customer other = (Customer) obj;
if(cid == null) {
if(other.cid != null)
return false;
}
else if(!cid.equals(other.cid))
return false;
if(customerId != other.customerId)
return false;
if(name == null) {
if(other.name != null)
return false;
}
else if(!name.equals(other.name))
return false;
return true;
}
public long getCustomerId() {
return customerId;
}
public void setCustomerId(long customerId) {
this.customerId = customerId;
}
public void addFeature(Feature feature) {
if(null == getFeatures()) {
features = new HashSet<Feature>();
}
features.add(feature);
}
public Set<Feature> getFeatures() {
return features;
}
public void setFeatures(Set<Feature> features) {
this.features = features;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public String getRandomKey() {
return randomKey;
}
public void setRandomKey(String randomKey) {
this.randomKey = randomKey;
}
public boolean hasFeatureNamed(String name) {
Set<Feature> features = getFeatures();
if (features == null) {
return false;
}
for (Feature feature : features) {
if (feature != null && feature.getName().equals(name)) {
return true;
}
}
return false;
}
public void removeFeature(String name) {
Set<Feature> features = getFeatures();
if (features == null) {
return;
}
for (Iterator<Feature> i = features.iterator(); i.hasNext();) {
Feature feature = i.next();
if (feature.getName().equals(name)) {
i.remove();
}
}
}
}
Looking at your Customer class, I cannot see how did you map the features set, but note that, however you did, the default fetching type is LAZY, meaning that your collection will not be initialized during the read.
Please try the following:
List<T> findByCriteriaImpl(List<String> fetches, Criterion... criterion) {
Criteria crit = createCriteria(getPersistentClass());
if (criterion != null) {
for (Criterion c : criterion) {
crit.add(c);
}
for (String s : fetches) {
crit.setFetchMode(s, FetchMode.JOIN);
}
}
long startTime = System.currentTimeMillis();
List<T> toReturn = crit.list();
reportQueryTimeForMonitoring(System.currentTimeMillis() - startTime, "findByCriteriaImpl", "for criteria " + crit);
return toReturn;
}
And call the findByCriteriaImpl like:
List<Customer> customers = findByCriteriaImpl(Collections.asList("features"), Restrictions.eq("cid", cid));
This way you can tell your method which collections you want to fetch together with your entity.
Related
I am currently developing an application in Java with FusionAuth, I am using the Java Client of that tool, and I want to create a user, so I use the createUser() method, which needs the UID and a UserRequest object, this one, need an User object which constructor is the next one:
UserRequest class
public class UserRequest {
public boolean sendSetPasswordEmail;
public boolean skipVerification;
public User user;
#JacksonConstructor
public UserRequest() {
}
public UserRequest(User user) {
this.sendSetPasswordEmail = false;
this.skipVerification = true;
this.user = user;
}
public UserRequest(boolean sendSetPasswordEmail, boolean skipVerification, User user) {
this.sendSetPasswordEmail = sendSetPasswordEmail;
this.skipVerification = skipVerification;
this.user = user;
}
}
User class
public class User extends SecureIdentity implements Buildable<User>, _InternalJSONColumn, Tenantable {
#InternalJSONColumn
#JsonMerge(OptBoolean.FALSE)
public final List<Locale> preferredLanguages = new ArrayList();
#JsonMerge(OptBoolean.FALSE)
private final List<GroupMember> memberships = new ArrayList();
#JsonMerge(OptBoolean.FALSE)
private final List<UserRegistration> registrations = new ArrayList();
public boolean active;
public LocalDate birthDate;
public UUID cleanSpeakId;
#JsonMerge(OptBoolean.FALSE)
public Map<String, Object> data = new LinkedHashMap();
public String email;
public ZonedDateTime expiry;
public String firstName;
public String fullName;
public URI imageUrl;
public ZonedDateTime insertInstant;
public ZonedDateTime lastLoginInstant;
public String lastName;
public String middleName;
public String mobilePhone;
public String parentEmail;
public UUID tenantId;
public ZoneId timezone;
public TwoFactorDelivery twoFactorDelivery;
public boolean twoFactorEnabled;
public String twoFactorSecret;
public String username;
public ContentStatus usernameStatus;
public User() {
}
public User(User user) {
this.active = user.active;
this.birthDate = user.birthDate;
this.cleanSpeakId = user.cleanSpeakId;
this.email = user.email;
this.encryptionScheme = user.encryptionScheme;
this.expiry = user.expiry;
this.factor = user.factor;
this.firstName = user.firstName;
this.fullName = user.fullName;
this.id = user.id;
this.imageUrl = user.imageUrl;
this.insertInstant = user.insertInstant;
this.lastLoginInstant = user.lastLoginInstant;
this.lastName = user.lastName;
this.memberships.addAll((Collection)user.memberships.stream().map(GroupMember::new).collect(Collectors.toList()));
this.middleName = user.middleName;
this.mobilePhone = user.mobilePhone;
this.parentEmail = user.parentEmail;
this.password = user.password;
this.passwordChangeRequired = user.passwordChangeRequired;
this.passwordLastUpdateInstant = user.passwordLastUpdateInstant;
this.preferredLanguages.addAll(user.preferredLanguages);
this.registrations.addAll((Collection)user.registrations.stream().map(UserRegistration::new).collect(Collectors.toList()));
this.salt = user.salt;
this.tenantId = user.tenantId;
this.timezone = user.timezone;
this.twoFactorDelivery = user.twoFactorDelivery;
this.twoFactorEnabled = user.twoFactorEnabled;
this.twoFactorSecret = user.twoFactorSecret;
this.username = user.username;
this.usernameStatus = user.usernameStatus;
this.verified = user.verified;
if (user.data != null) {
this.data.putAll(user.data);
}
}
public void addMemberships(GroupMember member) {
this.memberships.removeIf((m) -> {
return m.groupId.equals(member.groupId);
});
this.memberships.add(member);
}
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User user = (User)o;
this.sort();
user.sort();
return super.equals(o) && Objects.equals(this.active, user.active) && Objects.equals(this.birthDate, user.birthDate) && Objects.equals(this.cleanSpeakId, user.cleanSpeakId) && Objects.equals(this.data, user.data) && Objects.equals(this.email, user.email) && Objects.equals(this.expiry, user.expiry) && Objects.equals(this.firstName, user.firstName) && Objects.equals(this.fullName, user.fullName) && Objects.equals(this.imageUrl, user.imageUrl) && Objects.equals(this.insertInstant, user.insertInstant) && Objects.equals(this.lastLoginInstant, user.lastLoginInstant) && Objects.equals(this.lastName, user.lastName) && Objects.equals(this.memberships, user.memberships) && Objects.equals(this.middleName, user.middleName) && Objects.equals(this.mobilePhone, user.mobilePhone) && Objects.equals(this.registrations, user.registrations) && Objects.equals(this.parentEmail, user.parentEmail) && Objects.equals(this.tenantId, user.tenantId) && Objects.equals(this.timezone, user.timezone) && Objects.equals(this.twoFactorDelivery, user.twoFactorDelivery) && Objects.equals(this.twoFactorEnabled, user.twoFactorEnabled) && Objects.equals(this.twoFactorSecret, user.twoFactorSecret) && Objects.equals(this.username, user.username) && Objects.equals(this.usernameStatus, user.usernameStatus);
}
}
#JsonIgnore
public int getAge() {
return this.birthDate == null ? -1 : (int)this.birthDate.until(LocalDate.now(), ChronoUnit.YEARS);
}
#JsonIgnore
public String getLogin() {
return this.email == null ? this.username : this.email;
}
public List<GroupMember> getMemberships() {
return this.memberships;
}
#JsonIgnore
public String getName() {
if (this.fullName != null) {
return this.fullName;
} else {
return this.firstName != null ? this.firstName + (this.lastName != null ? " " + this.lastName : "") : null;
}
}
public UserRegistration getRegistrationForApplication(UUID id) {
return (UserRegistration)this.getRegistrations().stream().filter((reg) -> {
return reg.applicationId.equals(id);
}).findFirst().orElse((Object)null);
}
public List<UserRegistration> getRegistrations() {
return this.registrations;
}
public Set<String> getRoleNamesForApplication(UUID id) {
UserRegistration registration = this.getRegistrationForApplication(id);
return registration != null ? registration.roles : null;
}
public UUID getTenantId() {
return this.tenantId;
}
public boolean hasUserData() {
if (!this.data.isEmpty()) {
return true;
} else {
Iterator var1 = this.registrations.iterator();
UserRegistration userRegistration;
do {
if (!var1.hasNext()) {
return false;
}
userRegistration = (UserRegistration)var1.next();
} while(!userRegistration.hasRegistrationData());
return true;
}
}
public int hashCode() {
return Objects.hash(new Object[]{super.hashCode(), this.active, this.birthDate, this.cleanSpeakId, this.data, this.email, this.expiry, this.firstName, this.fullName, this.imageUrl, this.insertInstant, this.lastLoginInstant, this.lastName, this.memberships, this.middleName, this.mobilePhone, this.registrations, this.parentEmail, this.tenantId, this.timezone, this.twoFactorDelivery, this.twoFactorEnabled, this.twoFactorSecret, this.username, this.usernameStatus});
}
public String lookupEmail() {
if (this.email != null) {
return this.email;
} else {
return this.data.containsKey("email") ? this.data.get("email").toString() : null;
}
}
public Locale lookupPreferredLanguage(UUID applicationId) {
Iterator var2 = this.registrations.iterator();
UserRegistration registration;
do {
if (!var2.hasNext()) {
if (this.preferredLanguages.size() > 0) {
return (Locale)this.preferredLanguages.get(0);
}
return null;
}
registration = (UserRegistration)var2.next();
} while(!registration.applicationId.equals(applicationId) || registration.preferredLanguages.size() <= 0);
return (Locale)registration.preferredLanguages.get(0);
}
public void normalize() {
Normalizer.removeEmpty(this.data);
this.email = Normalizer.toLowerCase(Normalizer.trim(this.email));
this.encryptionScheme = Normalizer.trim(this.encryptionScheme);
this.firstName = Normalizer.trim(this.firstName);
this.fullName = Normalizer.trim(this.fullName);
this.lastName = Normalizer.trim(this.lastName);
this.middleName = Normalizer.trim(this.middleName);
this.mobilePhone = Normalizer.trim(this.mobilePhone);
this.parentEmail = Normalizer.toLowerCase(Normalizer.trim(this.parentEmail));
this.preferredLanguages.removeIf(Objects::isNull);
this.username = Normalizer.trim(this.username);
if (this.username != null && this.username.length() == 0) {
this.username = null;
}
this.getRegistrations().forEach(UserRegistration::normalize);
}
public void removeMembershipById(UUID groupId) {
this.memberships.removeIf((m) -> {
return m.groupId.equals(groupId);
});
}
public User secure() {
this.encryptionScheme = null;
this.factor = null;
this.password = null;
this.salt = null;
this.twoFactorSecret = null;
return this;
}
public User sort() {
this.registrations.sort(Comparator.comparing((ur) -> {
return ur.applicationId;
}));
return this;
}
public String toString() {
return ToString.toString(this);
}
}
So, my question is, how do I create an User Object?
That constructor is the only one that the class have besides the empty constructor. Also the class does not have any setters.
I looked at the source code for the library you're working with. The fields are all public, so you can create an empty constructor and then set them by doing user.name = xxxx.
I am looking for a working use case for the following :
#PostMapping("/add-gateway")
public String addGateway(ModelMap model, #Valid Gateway gateway, BindingResult result) {
if (result.hasErrors()) {
System.out.println("GatewayController has thrown error!");
return "gateway";
}
service.addGateway(gateway.getId(), gateway.getGatewayName(), gateway.getIpAddress(), gateway.getDevices());
return "redirect:/list-gateways";
}
Here is my Gateway class:
public class Gateway {
private String id;
private String gatewayName;
private String ipAddress;
private List<Device> devices;
#NotNull(message = "Empty gateway name not allowed!")
#Size(min = 5, message = "Enter at least 5 characters!")
public Gateway() {
super();
}
public Gateway(String id, String gatewayName, String ipAddress, List<Device> exampleDevices) {
super();
this.id = id;
this.gatewayName = gatewayName;
this.ipAddress = ipAddress;
this.devices = exampleDevices;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getGatewayName() {
return gatewayName;
}
public void setGatewayName(String gwName) {
this.gatewayName = gwName;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public List<Device> getDevices() {
return devices;
}
public void setDevices(ArrayList<Device> devices) {
this.devices = devices;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Integer.parseInt(id);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Gateway other = (Gateway) obj;
if (id != other.id) {
return false;
}
return true;
}
public Map<String, List<Device>> getGatewayAndDevices(Gateway gateway) {
return (Map<String, List<Device>>) new HashMap().put(gateway.getGatewayName(), gateway.getDevices());
}
#Override
public String toString() {
return String.format("Gateway [id=%s, gatewayName=%s, ipAddress=%s, devices=%s]", id, gatewayName, ipAddress,
devices);
}
}
The program fails on the returned "gateway" String, because one of the parameters of the Gateway constructor is an ArrayList of Objects, so that I never add a new Gateway to the list of Gateways and never return "redirect:/list-gateways"... I tried lots of workarounds for parsing the ArrayList to String, or using a Converter class, or playing with the initBinder method, however none of them seems to work here...I will greatly appreciate your help, because I need a working solution until the end of tomorrow! Many thanks in advance!
I have a code like this:
public interface BatchExecuteHistoryRepository extends JpaRepository<BatchExecuteHistory, Long> {
Page<BatchExecuteHistory> findByBatchExecuteHistoryIdBatchIdOrderByTimeEndAsc(String batchId, Pageable pageable);
}
Here is my database:
Here is what I got on my website:
Anyone know why the query does not work with Order By time_end ASC???
I tried findByBatchExecuteHistoryIdBatchId(String batchId, Pageable pageable) and got the same result
Notice that BatchExecuteHistoryId is a composite id, and batchId is a element of it
Update, here is my BatchExecuteHistory class:
public class BatchExecuteHistory implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private BatchExecuteHistoryId batchExecuteHistoryId;
#NotNull
#Size(max = 100)
#Column(name = "batch_name", length = 100, nullable = false)
private String batchName;
#NotNull
#Column(name = "status", nullable = false)
private Boolean status;
#NotNull
#Column(name = "time_end", nullable = false)
private Instant timeEnd;
#Size(max = 100)
#Column(name = "error_step", length = 100)
private String errorStep;
#Size(max = 100)
#Column(name = "error_content", length = 100)
private String errorContent;
#Column(name = "row_input")
private Long rowInput;
public BatchExecuteHistoryId getBatchExecuteHistoryId() {
return batchExecuteHistoryId;
}
public void setBatchExecuteHistoryId(BatchExecuteHistoryId batchExecuteHistoryId) {
this.batchExecuteHistoryId = batchExecuteHistoryId;
}
public Boolean getStatus() {
return status;
}
public String getBatchName() {
return batchName;
}
public BatchExecuteHistory batchName(String batchName) {
this.batchName = batchName;
return this;
}
public void setBatchName(String batchName) {
this.batchName = batchName;
}
public Boolean isStatus() {
return status;
}
public BatchExecuteHistory status(Boolean status) {
this.status = status;
return this;
}
public void setStatus(Boolean status) {
this.status = status;
}
public Instant getTimeEnd() {
return timeEnd;
}
public BatchExecuteHistory timeEnd(Instant timeEnd) {
this.timeEnd = timeEnd;
return this;
}
public void setTimeEnd(Instant timeEnd) {
this.timeEnd = timeEnd;
}
public String getErrorStep() {
return errorStep;
}
public BatchExecuteHistory errorStep(String errorStep) {
this.errorStep = errorStep;
return this;
}
public void setErrorStep(String errorStep) {
this.errorStep = errorStep;
}
public String getErrorContent() {
return errorContent;
}
public BatchExecuteHistory errorContent(String errorContent) {
this.errorContent = errorContent;
return this;
}
public void setErrorContent(String errorContent) {
this.errorContent = errorContent;
}
public Long getRowInput() {
return rowInput;
}
public BatchExecuteHistory rowInput(Long rowInput) {
this.rowInput = rowInput;
return this;
}
public void setRowInput(Long rowInput) {
this.rowInput = rowInput;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((batchExecuteHistoryId == null) ? 0 : batchExecuteHistoryId.hashCode());
result = prime * result + ((batchName == null) ? 0 : batchName.hashCode());
result = prime * result + ((errorContent == null) ? 0 : errorContent.hashCode());
result = prime * result + ((errorStep == null) ? 0 : errorStep.hashCode());
result = prime * result + ((rowInput == null) ? 0 : rowInput.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
result = prime * result + ((timeEnd == null) ? 0 : timeEnd.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;
BatchExecuteHistory other = (BatchExecuteHistory) obj;
if (batchExecuteHistoryId == null) {
if (other.batchExecuteHistoryId != null)
return false;
} else if (!batchExecuteHistoryId.equals(other.batchExecuteHistoryId))
return false;
if (batchName == null) {
if (other.batchName != null)
return false;
} else if (!batchName.equals(other.batchName))
return false;
if (errorContent == null) {
if (other.errorContent != null)
return false;
} else if (!errorContent.equals(other.errorContent))
return false;
if (errorStep == null) {
if (other.errorStep != null)
return false;
} else if (!errorStep.equals(other.errorStep))
return false;
if (rowInput == null) {
if (other.rowInput != null)
return false;
} else if (!rowInput.equals(other.rowInput))
return false;
if (status == null) {
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
if (timeEnd == null) {
if (other.timeEnd != null)
return false;
} else if (!timeEnd.equals(other.timeEnd))
return false;
return true;
}
#Override
public String toString() {
return "BatchExecuteHistory [" + batchExecuteHistoryId.toString() + ", batchName=" + batchName + ", status="
+ status + ", timeEnd=" + timeEnd + ", errorStep=" + errorStep + ", errorContent=" + errorContent
+ ", rowInput=" + rowInput + "]";
}
}
You should add a By before OrderBy, so your method should be: findByBatchExecuteHistoryIdBatchIdByOrderByTimeEndAsc
I think you don't miss naming.See Spring document
OrderBy
findByAgeOrderByLastnameDesc
… where x.age = ?1 order by x.lastname desc
It works well in my environment. I am using 2.6.0 version.
I recommand you check jpa version.and I can't see your BatchExecuteHistoryId class.
Anyway Try it for checking it works well in your environment.
Database
CREATE TABLE MEMBER
(
id character varying(10),
batch_id character varying(10),
create_datetime timestamp without time zone NOT NULL,
CONSTRAINT MEMBER_PK
PRIMARY KEY (id,batch_id)
);
INSERT into MEMBER (id,create_datetime,batch_id) VALUES ('USER1','2021/11/20 14:00:00','1');
INSERT into MEMBER (id,create_datetime,batch_id) VALUES ('USER2','2021/11/15 14:00:00','1');
INSERT into MEMBER (id,create_datetime,batch_id) VALUES ('USER3','2021/11/10 14:00:00','1');
Entity
#Entity(name = "Member")
#Table(name = "member")
#ToString
#Data
public class MemberEntity {
#EmbeddedId
private MemberPk batchExecuteHistoryId;
#Column(name = "create_datetime")
private LocalDateTime createDateTime;
}
Pk of Entity
#Embeddable
#ToString
public class MemberPk implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
#Column(name = "batch_id")
private String batchId;
}
Repository
#Repository
public interface MemberRepository extends JpaRepository<MemberEntity, String> {
public List<MemberEntity> findByBatchExecuteHistoryIdBatchIdOrderByCreateDateTimeAsc(String batchId, Pageable pageable);
}
Service
#Service
public class MemberService {
private final MemberRepository memberRepository;
#Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
#PostConstruct
public void findAllMember() {
List<MemberEntity> memberEntitys = memberRepository.findAll();
//MemberEntity(batchExecuteHistoryId=MemberPk(id=USER1, batchId=1), createDateTime=2021-11-20T14:00)
//MemberEntity(batchExecuteHistoryId=MemberPk(id=USER2, batchId=1), createDateTime=2021-11-15T14:00)
//MemberEntity(batchExecuteHistoryId=MemberPk(id=USER3, batchId=1), createDateTime=2021-11-10T14:00)
memberEntitys.forEach(System.out::println);
System.out.println("----------------------------");
//MemberEntity(batchExecuteHistoryId=MemberPk(id=USER3, batchId=1), createDateTime=2021-11-10T14:00)
//MemberEntity(batchExecuteHistoryId=MemberPk(id=USER2, batchId=1), createDateTime=2021-11-15T14:00)
List<MemberEntity> memberEntitysWithOrderBy = memberRepository.findByBatchExecuteHistoryIdBatchIdOrderByCreateDateTimeAsc("1",PageRequest.of(0, 2));
memberEntitysWithOrderBy.forEach(System.out::println);
}
}
I have a Canteen class and a Course class (and a BaseEntity). The Canteen class has a set of courses. A course is unique if the composition of name, dateOfServing and the canteen id is unique. I tried to write a test case which should throw an exception if a non-unique course is added to a canteen. But the test doesn't throw any exception at all. Which leads me to believe that I'm doing me Canteen and Course class wrong. The test in question is addDuplicatedCourseToCanteenTest. Anyone got a clue about what I'm doing wrong?
I'm new to TDD as well so any critique in that area is very welcome as well.
BaseEntity.java
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
long id;
private Date createdAt;
private Date updatedAt;
// TODO: http://stackoverflow.com/a/11174297/672009
// Using the above we wouldn't have to created a CommentRepository
// Is that a good idea?
/**
* http://www.devsniper.com/base-entity-class-in-jpa/
*/
/**
* Sets createdAt before insert
*/
#PrePersist
public void setCreationDate() {
this.setCreatedAt(new Date());
}
/**
* Sets updatedAt before update
*/
#PreUpdate
public void setChangeDate() {
this.setUpdatedAt(new Date());
}
public Date getCreatedAt() {
return createdAt;
}
protected void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
protected void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
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 != other.id)
return false;
return true;
}
}
Canteen.java
#Entity
public class Canteen extends BaseEntity {
private String name;
// TODO: https://schuchert.wikispaces.com/JPA+Tutorial+1+-+Embedded+Entity
// http://docs.oracle.com/javaee/6/api/javax/xml/registry/infomodel/PostalAddress.html
//private Address address;
//private PostalAddress postalAddress;
/**
* In honor of KISS I simply use a simple string address as a holder for the restaurants address.
* The idea is that the string will contain an address which will be valid according to google maps.
* Same goes for openingHours, phoneNumber and homepage... KISS wise.
*/
private String address;
private String openingHours; // A string which will be presented within a pre tag
// Eg. <pre>Mandag - Torsdag 10-22
// Fredag - Lørdag 10-24
// Søndag 11-20</pre>
private String contact;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Course> courses = new HashSet<>();
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 getOpeningHours() {
return openingHours;
}
public void setOpeningHours(String openingHours) {
this.openingHours = openingHours;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
public boolean addCourse(Course course)
{
return getCourses().add(course);
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
Canteen other = (Canteen) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
Course.java
#Entity
public class Course extends BaseEntity {
private String name;
private Date dateOfServing;
#ManyToOne
private Canteen canteen;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDateOfServing() {
return dateOfServing;
}
public void setDateOfServing(Date dateOfServing) {
this.dateOfServing = dateOfServing;
}
public Canteen getCanteen() {
return canteen;
}
public void setCanteen(Canteen canteen) {
this.canteen = canteen;
}
#Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((canteen == null) ? 0 : canteen.hashCode());
result = prime * result
+ ((dateOfServing == null) ? 0 : dateOfServing.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
Course other = (Course) obj;
if (canteen == null) {
if (other.canteen != null)
return false;
} else if (!canteen.equals(other.canteen))
return false;
if (dateOfServing == null) {
if (other.dateOfServing != null)
return false;
} else if (!dateOfServing.equals(other.dateOfServing))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
CanteenHasCoursesTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = PersistenceConfig.class)
public class CanteenHasCoursesTest {
#Autowired
private CanteenRepository canteenRepository;
private String canteenName;
private String courseName;
private Canteen canteen;
private Course course;
#Before
public void setUp() {
// Generate unique random name
canteenName = UUID.randomUUID().toString();
// Generate unique random name
courseName = UUID.randomUUID().toString();
// Create new canteen
canteen = new Canteen();
canteen.setName(canteenName);
// Create new course
course = new Course();
course.setName(courseName);
}
#Test
public void addCourseToCanteenTest() {
// Add course
canteen.addCourse(course);
// Save canteen
canteenRepository.save(canteen);
// Find it again
Canteen c = canteenRepository.findOne(canteen.getId());
// Confirm attributes are as expected
assertNotNull(c);
Set<Course> courses = c.getCourses();
Iterator<Course> it = courses.iterator();
assertTrue(it.hasNext());
Course course = it.next();
assertEquals(courseName, course.getName());
}
// TODO: expect some data violation exception
// #Test(expected = IndexOutOfBoundsException.class)
#Test
public void addDuplicatedCourseToCanteenTest() {
// Add course
canteen.addCourse(course);
// Add it again
canteen.addCourse(course);
// Save canteen
canteenRepository.save(canteen);
}
#After
public void tearDown() {
canteenRepository = null;
canteenName = null;
courseName = null;
canteen = null;
course = null;
}
}
My entity class is
#Entity
public class Student_enroll implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private int level_num;
private int term;
private String student_session;
private HashMap<String,Integer>mark_value;
#OneToOne
private Student student;
public String getStudent_session() {
return student_session;
}
public void setStudent_session(String student_session) {
this.student_session = student_session;
}
public int getLevel_num() {
return level_num;
}
public void setLevel_num(int level_num) {
this.level_num = level_num;
}
public int getTerm() {
return term;
}
public void setTerm(int term) {
this.term = term;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public HashMap<String, Integer> getMark_value() {
return mark_value;
}
public void setMark_value(HashMap<String, Integer> mark_value) {
this.mark_value = mark_value;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#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 Student_enroll)) {
return false;
}
Student_enroll other = (Student_enroll) 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 "com.domain.Student_enroll[ id=" + id + " ]";
}
}
and my controller function is
#RequestMapping(value="/add_mark",method = RequestMethod.POST)
public void add_mark(HttpServletRequest req){
HashMap<String,Integer>map=new HashMap<String,Integer>();
int level=Integer.parseInt(req.getParameter("level"));
int term=Integer.parseInt(req.getParameter("term"));
Student_enroll enroll=student_service.get_student_enroll(level, term);
List<Course>list_course=course_service.list_course(level, term);
Iterator<Course>itr=list_course.iterator();
while(itr.hasNext()){
enroll.put(itr.next().getCourse_Code(),75);
}
enroll.setMark_value(map); // Set hashmap
student_service.update_student_enroll(enroll);
}
I want to set the HashMap by using setHashmap() and want to persist the entity in database.is it an appropriate way cause when I want to persist it other attribute of entity is persisted but the hashmap attribute contains a BLOB object.
How to persist a hashmap of primitive type?
JPA supports Map persistencse using #MapKey, #MapKeyJoinColumn ... annotations
Refer to following article for details:
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Maps