Obtaining ENUM description in Java based on value - java

I'm new to ENUMs so I want to make sure I'm doing all of this right before I perform a little surgery on my models. My ENUM has a shorter string that's stored in the database known as the name, and a description which is what the user sees. My objective is to get the description for a content object to show on the page.
Of course
<td valign='top'><strong>Paperless:</strong> ${content.getPaperless()}</td>
won't do it because that'll only show EDELIVERY_REQUIRED. How do I need to adjust this to make it function properly?
My edit page works great:
<td valign='top'>
<strong>Go Paperless Messaging</strong><br/>
<form:select path="paperless">
<form:options items="${paperlessEnumValues}" itemValue="name" itemLabel="description"/>
</form:select>
</td>
My enum:
public enum Paperless {
NONE(null, ""),
EDELIVERY_RECOMMENDED("EDELIVERY_RECOMMENDED", "Recommend eDelivery"),
EDELIVERY_REQUIRED("EDELIVERY_REQUIRED", "Require eDelivery"),
EDELIVERY_REQUIRED_JUSTIFICATION("EDELIVERY_REQUIRED_JUSTIFICATION", "Require eDelivery w/out justification");
private String name;
private String description;
Paperless(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
}
My Model
public class Content implements Serializable {
...
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "paperless")
private String paperless;
...
public String getPaperless() {
return paperless;
}
public void setPaperless(String paperless) {
this.paperless = paperless;
}
My content service
private List<Content> findContentEntities(boolean all, int maxResults, int firstResult) {
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Content.class));
Query q = em.createQuery(cq);
if (!all) {
q.setMaxResults(maxResults);
q.setFirstResult(firstResult);
}
return q.getResultList();
} finally {
em.close();
}
}

Map private Paperless paperless in your entity, rather than a String. JPA supports enum mapping
Use ${content.paperless.description}

Related

Dynamically Query from List or two different entities

I have an entity called Person, inside that basic metadata, then inside that Tag and Language. I want to get all rows that contain specific tag name and language.
I came to know about Criteria Query about. How can we interlink two different entities together?
Example: Get all rows having the tag as Model and language as English.
#Entity
public Person {
#Id
private String id;
private BasicMetadata basicMetadata;
-----------
}
Basic Metadata table
#Entity
public BasicMetadata {
#Id
private String id;
private List<Tag> tags;
private List<Language> language;
-------------
}
Tag Table
#Entity
public Tag {
#Id
private String id;
private String name;
-------------
}
Language Table
#Entity
public Language{
#Id
private String id;
private String name;
-------------
}
I created a simple method for specification Query is that correct
private Specification<Person> containsText(String keyword) {
return (root,query, builder) -> {
String finalText = keyword.toLowerCase();
if (!finalText.contains("%")) {
finalText = "%" + finalText + "%";
}
Predicate genreExp = builder.like(builder.lower(root.get("basicMetadata").get("tags")), finalText);
return builder.or(genreExp);
};
you can write your specification like this
public class PersonSpecifications {
public static Specification<Person> hasTag(String keyword) {
return (root, query, builder) -> {
String finalText = keyword.toLowerCase();
if (!finalText.contains("%")) {
finalText = "%" + finalText + "%";
}
Join<Person, BasicMetaData> md = root.join("basicMetaData");
return builder.like(builder.lower(md.join("tags").get("name")), finalText);
}
}
}
and you can use this specification to get the filtered results like this
repository.findAll(PersonSpecifications. hasTag("abc"),PageRequest,of(0,10));

add data to database (related tables) Spring Boot

I know English badly, but i'm trying to describe my problem.
I'm new in Spring. And I have some problems with adding data to my database.I have to table Pc and Pc characteristics. They are related by Id. It's easy to add data in non realted table, but how can I add data in related table? What shoud I write in my Controller? There are some classes below.
Pc class:
#Entity
#Table(name = "pc")
public class Pc {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int price;
public Pc(){}
public Pc(String name, int price) {
this.name = name;
this.price = price;
}
#OneToMany
#JoinColumn(name = "pc_id")
private List<PcChars> chars = new ArrayList<>();
public List<PcChars> getChars() {
return chars;
}
public void setChars(List<PcChars> chars) {
this.chars = chars;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
PcChars class:
#Entity
#Table(name = "pcChars")
public class PcChars {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String value;
public PcChars(){}
public PcChars(String name, String value) {
this.name = name;
this.value = value;
}
#ManyToOne
private Pc pc;
public Pc getPc() {
return pc;
}
public void setPc(Pc pc) {
this.pc = pc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
PcCharactsController:
#Controller
public class PcCharactsController {
final private PcRepo pcRepo;
final private PcCharRepo pcCharRepo;
public PcCharactsController(PcRepo pcRepo, PcCharRepo pcCharRepo) {
this.pcRepo = pcRepo;
this.pcCharRepo = pcCharRepo;
}
//Pc characteristics list
#GetMapping("pc/{id}/")
public String pcCharList(#PathVariable int id, Model model) throws Exception{
Pc pc = pcRepo.findById(id).orElseThrow(() -> new Exception("PostId " +
id + " not found"));
List<PcChars> pcChars = pc.getChars();
model.addAttribute("model", pc.getName());
model.addAttribute("pcChars", pcChars);
return "charList";
}
//add characteristic
#PostMapping("pc/{id}/")
public String addCharact(){
return "charList";
}
Characteristics.ftl:
<html>
<head>
<title>Ho</title>
</head>
<body>
<div>
<form method="post" action="/pc/${id}/">
<input type="text" name="name">
<input type="text" value="value">
<input type="hidden" name="pc_id" value="${id}">
<button type="submit">Add</button>
</form>
</div>
</body>
</html>
Since you are not using any modelAttribute to bind the input values straight to a POJO you can use simple HttpServletRequest to get the input attributes, use them to create the object you want to store and store it using Hibernate
#PostMapping("pc/{id}/")
public String addCharact(HttpServletRequest req){
String name = req.getParameter("name");
String value = req.getParameter("value");
String id = req.getParameter("id");
PcChars pcchars = new PcChars(name,value,id); // create the corresponding constructor
SessionFactory sessionFactory;
Session session = sessionFactory.openSession();
Transaction tx = null;
try{
tx = session.getTransaction();
tx.begin();
session.save(pcchars);
tx.commit();
}
catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return "charList";
}
The part of Spring you're using is called Spring data, a library that allows you to use JPA in your Spring application. JPA is a specification for frameworks called ORM (Object-relationnal mapping).
To keep it simple, in your code, you do not use the relational approach anymore, but an object approach. Annotations you put on your classes' fields are used to define mappings between them and your database tables and fields.
So, you don't have to insert both entities separately anymore. You need to create a Pc instance, then to create a PcChars one, and finally to add the chars into the pc's chars list, like this :
Pc myPc = new Pc();
PcChars myChars = new PcChars();
myPc.getChars().add(myChars);
And when you'll use your repository to save the modifications with this :
pcRepo.save(myPc);
The JPA implementation will automatically do the work for you :
Inserting the row corresponding to your PC instance in the PC table
Inserting the row corresponding to your PC chars in the the PC_CHARS table
Settings the PC_CHARS.PC_ID with the ID of the freshly inserted PC instance's id in order to create the reference between them.
Not sure, but I think the ORM also do this when you add your chars to the pc instance :
myChars.setPc(myPc);
in order to make the bound between both instances reciprocal.
Note that I used arbitrary field names according to your schema.
I strongly suggest you to give responsibility of relationship to child side when using #OneToMany relation.
Modify your parent class as below:
#OneToMany(cascade = CascadeType.ALL, mappedBy="pc")
#BatchSize(size = 10)
private List<PcChars> chars = new ArrayList<>();
public void addPcChar(PcChar pcChar) {
this.chars.add(pcChar);
pcChar.setPc(this);
}
On the child class:
#ManyToOne
#JoinColumn(name = "pc_id")
private Pc pc;
Now you can persist your parent with child as below :
Pc pc = new Pc();
PcChar pcChar = new PcChar();
pc.addPcChar(pcChar);
If you use spring boot data repository, it saves it correctly as below
// assume your repository like below
public interface PcRepository extends CrudRepository<Pc, Integer> {}
// in your service or whatever in some place
pcRepository.save(pc);
With saving hibernate entity manager:
EntityManagerFactory emfactory =
Persistence.createEntityManagerFactory("Hibernate");
EntityManager entitymanager = emfactory.createEntityManager();
entitymanager.getTransaction().begin();
entitymanager.persist(pc);
entitymanager.getTransaction().commit();
entitymanager.close();
emfactory.close();
For detailed information about hibernate relationship take a look at my post : https://medium.com/#mstrYoda/hibernate-deep-dive-relations-lazy-loading-n-1-problem-common-mistakes-aff1fa390446

How to map Form Parameter with Hibernate Entity Class in Spring-MVC Controller [duplicate]

This question already has an answer here:
Binding child object on submit spring mvc
(1 answer)
Closed 5 years ago.
I am new at Hibernate/JPA and I am trying to get form parameter with hibernate entity class. There was no problem with it until when I tried to get parameter with Entity class that has relationship with other class. For example;
Controller:
#RequestMapping(value = "/addProduct", method = RequestMethod.POST)
public String addProduct(Model model, Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Entity class:
#Entity
#Table(name = "products")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private Category category;
#Column(name = "name")
private String name;
#Column(name = "price")
private String price;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
Category class :
#Entity
#Table(name = "categories")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The program cannot set 'category'. Because category is not type like int, string.. I am realize the problem. But I cannot find solution to mapping parameters with Entity class. Is there any way to solve this. Or should I use #RequestParam to get parameters one-by-one instead of mapping parameters with entity class.
UPDATE
I just change category to category.id in my .jsp page and it solved my problem.
old code
<form>
...
<select class="form-control" name="category">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
new code
<form>
...
<select class="form-control" name="category.id">
<c:if test="${not empty categoryList}">
<c:forEach var="item" items="${categoryList}">
<option value="${item.getId()}">${item.getName()}</option>
</c:forEach>
</c:if>
</select>
</form>
Please show us your form mapping,
Till then can could try with, change path in <form:select>/<form:input> tag to category.id and category.name
have a look at my another answer
I will suggest don't expose your Entity in the View, try to get form data in DTO, then convert to entity..
One way to do that is by creating a custom Spring Converter. So lets say you will be passing your entity's Id as a path variable, and your converter implementation would get that product object for you.
In your Controller you will need to do the following:
#RequestMapping(value = "/addProduct/{id}", method = RequestMethod.POST)
public String addProduct(Model model, #PathVariable("id") Product product) {
databaseService.insert(product);
return "redirect:/products";
}
Your Converter would look something like this:
import org.springframework.core.convert.converter.Converter;
public class StringToProductConverter implements Converter<String, Product> {
...
#Override
public Product convert(String id) {
Product product = databaseService.getProduct(id);
...
return product;
}
And don't forget to register your Converter either programmatically or by XML depending on your Spring version you're working on.

Binding objects from spring multiple <form:select>

Have to beans:
#Entity
#Table(name="book")
public class Book {
#Id
#Column(name="id_book")
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy="increment")
private int id;
#Column
#Size(min=1,max=100)
private String title;
#Column
#Size(min=1,max=400)
private String description;
#Column
private Integer year=0;
#ManyToMany(cascade={CascadeType.ALL},fetch = FetchType.EAGER)
#Fetch (FetchMode.SELECT)
#JoinTable(name="book_author",
joinColumns={#JoinColumn(name="book_id_book")},
inverseJoinColumns= {#JoinColumn(name="author_id_author")})
private List<Author> author=new ArrayList<Author>();
//getters/setters
}
and:
#Entity
#Table(name="author")
public class Author {
#Id
#Column(name="id_author")
#GeneratedValue
private Integer id;
#Column
private String name;
#Column
private String surname;
#ManyToMany(mappedBy="author")
private Set<Book> book=new HashSet<Book>();
//getters/setters
}
In my jsp I'm have form for enter data about book, and multiple list for select author(s) from DB, problem only in select authors, therefore give only this code:
<sf:select multiple="true" path="author" items="${authors}" size="7" >
</sf:select>
Where ${authors} - List with objects Author from DB. Use POST request.
In my controller for this page have this (I know it's not correct):
#RequestMapping(value="/addbook", method=RequestMethod.POST)
public String addBook(Book book){
hibarnateService.saveBook(book);
return "redirect:/books";
}
When I'm create book without select authors, but enter another information, all fine, book save in DB. When select some authors get this - The request sent by the client was syntactically incorrect.
Problem solved by add in controller:
#InitBinder
protected void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Author.class, new Editor(hibarnateService));
}
and create class:
public class Editor extends PropertyEditorSupport {
private final Dao hibernateService;
public Editor(Dao hibernateService){
this.hibernateService=hibernateService;
}
#Override
public void setAsText(String text) throws IllegalArgumentException{
Author author=hibernateService.getAuthor(Integer.parseInt(text));
setValue(author);
}
}
P.S. What wrong with me? I can't find the right answer myself until I ask here)
You will need to implement initBinder in your controller, below can be tentative code (not tested)
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(List.class, "authors ", new CustomCollectionEditor(List.class)
{
#Override
protected Object convertElement(Object element)
{
Long id = null;
if(element instanceof Long) {
//From the database 'element' will be a Long
id = (Long) element;
}
return id != null ? authorService.loadAuthorById(id) : null;
}
});
}

JSF 2.0 "Conversion Error setting value 'courseID' for 'null Converter'.!!How can I avoid this kinda error? [duplicate]

This question already has answers here:
Conversion Error setting value for 'null Converter' - Why do I need a Converter in JSF?
(2 answers)
Closed 7 years ago.
I am working on a web application using PrimeFaces, JPA, Hibernate and JSF 2.0.
I have two entities Students and Course with an many to one relationship.
#Entity
#Table(name = "STUDENTS")
public class Students extends MainUsers implements Serializable {
private String firstName;
private String lastName;
private long mobile;
private String jobTitle;
private int duration;
#Temporal(TemporalType.TIMESTAMP)
private Date startDate;
#Temporal(TemporalType.TIMESTAMP)
private Date endDate;
#ManyToOne
#JoinColumn(name = "course_id", nullable = true)
private Course company;
// Getters and setters.
}
#Entity
#Table(name = "COURSE")
#NamedQueries({
#NamedQuery(name = "course.findCourseByCourseId", query = "select c from Course c where c.Id =:id"),
#NamedQuery(name = "course.findCourseByCourseName", query = "select c from Course c where c.courseName =:courseName") })
public class Course implements Serializable {
public static final String FIND_COURSE_BY_COURSE_ID = "course.findByCourseId";
public static final String FIND_COURSE_COURSE_NAME = "course.findByCourseName";
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
private String courseName;
#OneToMany(targetEntity = Students.class, mappedBy = "course", fetch = FetchType.LAZY)
private List<Students> students;
// Getters and setters.
#Override
public int hashCode() {
return getId();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Course) {
Course course = (Course) obj;
return course.getId() == Id;
}
return false;
}
}
I have a registration page where it takes student's names, email, password and course. For selecting the course I have used this
<h:outputText value="Course :" />
<p:selectOneMenu value="#{courseMB.course}">
<f:selectItem itemLabel="Select one Course" itemValue="" />
<f:selectItems value="#{courseMB.allCourses}" var="crs"
itemLabel="#{crs.courseName}" itemValue="#{crs.id}" />
<f:converter converterId = "courseConverter"/>
</p:selectOneMenu>
To create a student I have the following method in StudentMB class:
public void createStudent() {
String test = student.getEmail();
if (getStudentFacade().isStudentExist(test)){
System.out.println(test);
} else {
try {
student.setActivation_key(hashKey());
student.setRole(Role.STUDENT);
student.setActive(0);
getStudentFacade().createStudent(student);
displayInfoMessageToUser("Created with success");
SendEmail.Send(username, password, student.getEmail(), title, linkToSend());
loadStudent();
resetStudent();
} catch (Exception e) {
displayErrorMessageToUser("Opps, we could not create the user. Try again");
e.printStackTrace();
}
}
}
I don't really know how to get the course into StudentMB and persist that into the database. The current methodology gives me an error
Conversion Error setting value 'courseID' for 'null Converter'.
I tried to use a converter but I am getting empty string into the argument.
#FacesConverter(value="courseConverter", forClass = com.model.Course.class)
public class CourseConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
CourseFacade courseFacade = new CourseFacade();
int courseId;
try {
courseId = Integer.parseInt(submittedValue);
} catch (NumberFormatException exception) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Type the name of a Course and select it (or use the dropdown)",
"Type the name of a Course and select it (or use the dropdown)"));
}
return courseFacade.findCourse(courseId);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
Course course = null;
if (modelValue instanceof Course){
course = (Course) modelValue;
StringBuilder asString = new StringBuilder();
asString.append(course.getId()+"-");
asString.append(course.getCourseName());
return asString.toString();
}
return "";
}
}
How is this caused and how can I solve it?
You need to set the select item value to the Course itself, not to its id.
Replace
itemValue="#{crs.id}"
by
itemValue="#{crs}"
Otherwise the converter would only get the #{crs.id} as modelValue in getAsString() and thus return an empty string. This empty string is in turn submitted back to the server through getAsObject() which in turn causes the exception.
You should have thrown a ConverterException in the else part of the if (modelValue instanceof Course) so that it was immediately clear that the converter isn't suitable for the given model value.
See also:
Our selectOneMenu wiki page

Categories

Resources