Hibernate selecting strings and not objects - java

I'm new to the Hibernate world, and I have a problem that I couldn't solve myself. And please be nice.
What I have :
Netbeans IDE 8.0.2
Mysql database (easyPHP) with some tables
What I want :
Select categories (table) which has 3 records with id,name, and description and show them (name and description) in jsp using EL.
My Category Class:
public class Category implements java.io.Serializable {
private Integer id;
private String name;
private String description;
public Category() {
}
public Category(String name, String description) {
this.name = name;
this.description = description;
}
public Category(String name, String description) {
this.name = name;
this.description = description;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
My getCategories method :
public static List getAllCategories(){
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
List results = session.createCriteria(Category.class, "category")
.list();
tx.commit();
return results;
}
My Controller:
List categories = CategoriesManagement.getAllCategories();
map.addAttribute("categories", categories);
My view (jsp):
<c:forEach var="cat" items="${categories} ">
${cat.name}
</c:forEach>
I'm getting nothing.
And when I show ${cat.class} it says :
java.lang.String
java.lang.String
java.lang.String
And when I show ${cat} it says :
com.company.Category#7136faa
com.company.Category#25636faa
com.company.Category#83baeaa
Update :
When I redefine toString() method in Category like this :
public toString(){
return "foo";
}
I get :
[foo
foo
foo]
Thanks in advance.

Use this: <c:out value="${cat.name}" />

I know it's wierd and after 9 hours I found that the space in
<c:forEach var="cat" items="${categories} "> was the error,
I should do as :
<c:forEach var="cat" items="${categories}">

Related

Api endpoint that edits one element in list

I am currently building a rest api that lets the user enter a recipe and describe it. I am using spring-boot as backend and angularjs as frontend.
This is springboot recipe file
package com.example.springboot;
import com.example.springboot.Recipe;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
#Entity // This tells Hibernate to make a table out of this class
public class Recipe {
public Recipe(){
}
public Recipe(Integer id, String name, String description, String type, Integer preptime, Integer cooktime, String content, Integer difficulty){
this.id = id;
this.name = name;
this.description = description;
this.type = type;
this.preptime = preptimee;
this.cooktime = cooktime;
this.content = content;
this.difficulty = difficulty;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String description;
private String type;
private Integer preptime;
#Column(columnDefinition = "TEXT")
private String content;
private Integer difficulty;
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getDifficulty() {
return difficulty;
}
public void setDifficulty(Integer difficulty) {
this.difficulty = difficulty;
}
public Integer getpreptime {
return preptime;
}
public void setpreptime(Integer preptime) {
this.preptime = preptime;
}
}
I created an Endpoint where the user can edit the whole recipe. The user can edit the name , description, content and so on in the recipes/edit/{id} endpoint.
The Endpoint looks like this.
#PutMapping("/recipes/edit/{id}")
void updateRecipe(#PathVariable int id, #RequestBody Recipe recipe ) {
System.out.println("entering");
Recipe recipe_ = recipeRepository.findById(id).get();
recipe_.setName(recipe.getName());
recipe_.setDescription(recipe.getDescription());
recipe_.setType(recipe.getType());
recipe_.setpreptime(recipe.getpreptime());
recipe_.setContent(recipe.getContent());
System.out.println("entering " + recipe.getTitle());
System.out.println("entering" + recipe.getType());
System.out.println("entering" + recipe.getDescription());
System.out.println("adding");
recipeRepository.save(recipe_);
}
Now I just want to create an Endpoint which only serves the purpose for renaming the name of the recipe. This putmapping should accept a list as its input then only rename the name of the recipe.
#PutMapping("/recipes/rename")
public List<Recipe> {
System.out.println("entering renaming");
// recipe_.setName(recipe.getName()); ?
}
I don't know how I can implement this. This is what I have come up with so far. An endpoint which takes a list as a parameter.
This is the service.ts file that updates the Recipes in the edit function
service.ts:
updateRecipe (id: number, recipe: any): Observable<any > {
const url = `${this.usersUrl}/edit/${id}`;
return this.http.put(url ,recipe);
}
where the updateRecipe gets called:
save(): void {
const id = +this.route.snapshot.paramMap.get('name');
this.recipeService.updateRecipe2(id, this.recipes)
.subscribe(() => this.gotoUserList());
}
This implementation work , I don't know how I can get it work or how I can rewrite the functions so that it can update only the name of the recipe and not the whole file.
Could someone help me?
Your update the name method should look like that:
#PutMapping("...{id}")
public void updateName(#PathVariable Integer id, #RequestParam String name){
Recipe recipe = repository.findById(id).orElseThrow(...);
recipe.setName(name);
}
if you want to rename list of recipes
public void renameRecipes(String oldName, String newName){
repository.findByName(oldName)
.forEach(r -> r.setName(newName));
}
#PutMapping("recipes/rename")
public void updateNames(#PequestParam String oldName, #RequestParam String newName){
renameRecipes(oldName, newName);
}
Try that.

Java multiple join query

I am trying to create a REST service in Java with Spring Boot.
I have 2 tables Topic and Course and i want to retrieve NAME and DESCRIPTION from Topic and PRICE from Course.
The connection between these 2 tables is made with TOPIC_ID from Course.
Result MUST be a JSON.
[
{
"id": "course1",
"name": "name course1",
"description": "course1"
},
{
"id": "course2",
"name": "course2 name",
"description": "course2"
},
{
"id": "course3",
"name": "course3 name",
"description": "course3"
}
]
The query is below.
I know it's possible with DTO and JPA but I need to write a lot of code for a simple database query.
Thank you.
package com.example.course;
import com.example.topic.Topic;
import javax.persistence.*;
#Entity
#Table(name = "topic", schema = "topic")
public class Topic {
#Id
private String id;
private String name;
private String description;
public Topic() {
}
public Topic(String id, String name, String description) {
this.id = id;
this.name = name;
this.description = description;
}
public String getDescription() {
return description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDescription(String description) {
this.description = description;
}
}
package com.example.topic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "course", schema = "topic")
public class Course {
#Id
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name="PRICE")
private Integer price;
#ManyToOne
#JoinColumn(name="TOPIC_ID", nullable=false)
private Topic topic;
public Course() {
}
public Course(String id, String name, String description, String topicId) {
this.id = id;
this.name = name;
this.description = description;
this.topic = new Topic(topicId, "", "");
}
public String getDescription() {
return description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setDescription(String description) {
this.description = description;
}
public Topic getTopic() {
return topic;
}
public void setTopic(Topic topic) {
this.topic = topic;
}
public void setPrice(Integer price) { this.price = price; }
public Integer getPrice() { return price; }
}
package com.example.dto;
public class TopicDescDTO {
private String id;
private String name;
private String description;
public TopicDescDTO(String id, String name, String description) {
this.id = id;
this.name = name;
this.description = description;
}
public TopicDescDTO() {
}
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;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
select t.name, t.description, c.price as course_price
from topic.course c
inner join topic.topic t on t.id = c.topic_id
Take advantage of the projection interface offered by Spring Data JPA:
public interface TopicDescDTO{
Integer getPrice();
String getName();
String getDescription();
}
and then just land a proper method in one of your repositories:
#Query(select t.name, t.description, c.price
from Course c
inner join c.topic t)
List<TopicDescDTO> getTopicDescs();
Spring will do the mapping for you.

thymeleaf spring th attribute nested loop

This webapp is made with spring boot connected to MariaDB .I would like to view the items in each category, I can see the category attributes and can see the item in the view as such [Item [id=1, title=test, description=11, status=Used, zipcode=1231, price=111.0, category=Category [id=3, type=Services]]]
heres my controller
#RequestMapping(value="/item-by-category/{id}",method= RequestMethod.GET)
public String itemByCategory(#PathVariable("id") Long categoryid, Model model){
//model.addAttribute("items",irepository.findByCategory(categoryid));
model.addAttribute("categorys",crepository.findOne(categoryid));
//model.addAttribute("item",irepository.findByCategory(categoryid));
return "/item-by-category";
}
Im using CRUD repositories so I tried to use the itemRepository method to filter the items by category but I get an error on the type of attribute passed even if its of type Long as stated in the class initiation.
Repositories:
public interface ItemRepository extends CrudRepository<Item, Long> {
List<Item> findByTitle(String title);
List<Item> findByCategory(Long categoryid);
}
public interface CategoryRepository extends CrudRepository<Category, Long> {
//find by cat type
List<Category> findByType(String type);
//List<Category>findByItem(String item);
//Item findByCategory(String type);
//show the items in the categories
//List<Item>items(String type);
//List<Category>findByItem(String item);
}
classes :
#Entity
#Table(name="category")
public class Category {
//#id creates an ID column for the table
#Id
//Generates automatically a unique PK for every new entity object
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="categoryid")
private Long id;
#Column(name="type")
private String type;
// 1 Category can have * Items
#OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
private List<Item> item;
//constructor
public Category() {}
public Category(String type) {
super();
this.type = type;
}
//getters n setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
//getters n setters for relationship
public List<Item> getItems() {
return item;
}
public void setItems(List<Item> item) {
this.item = item;
}
#Override
public String toString() {
return "Category [id=" + id + ", type=" + type + "]";
}
}
#Entity
#Table(name="item")
public class Item {
//generated ID column
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="itemid")
private Long id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
#Column(name="status")
private String status;
#Column(name="zipcode",length=5)
private Integer zipcode;
#Column(name="price")
private Double price;
//create relationship or * to 1 between items to user
/*
#ManyToOne
#JsonIgnore
#JoinColumn(name = "userid")
private User user;
*/
//Many items can have 1 category * to 1
#ManyToOne
/*entity relationship will
cause endless loop (First item is serialized and it contains
category which is then serialized which contains students which
are then serialized
*/
#JsonIgnore
#JoinColumn(name = "categoryid")
private Category category;
//working ^^
//JPA constructor
public Item(){
}
public Item(Long id, String title, String description, String status, Integer zipcode, Double price,
Category category) {
super();
this.id = id;
this.title = title;
this.description = description;
this.status = status;
this.zipcode = zipcode;
this.price = price;
this.category = category;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getZipcode() {
return zipcode;
}
public void setZipcode(Integer zipcode) {
this.zipcode = zipcode;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
#Override
public String toString() {
return "Item [id=" + id + ", title=" + title + ", description=" + description + ", status=" + status
+ ", zipcode=" + zipcode + ", price=" + price + ", category=" + category + "]";
}
}
so tried taking the category and got it working so far like this:
<table class="table table-striped">
<tr th:each ="category : ${categorys}">
<td th:text="${category.id}" ></td>
<td th:text="${category.items}" ></td>
//shows the size of the array
<td th:text="${category.items.size()}" ></td>
</tr>
<!-- this is what I want as the result, I would like to know how to loop with the TH attribute
<tr>
<td th:text="${category.items[0].title}"></td>
<td th:text="${category.items[0].category.type}"></td>
<td th:text="${category.items[0].description}"></td>
<td th:text="${category.items[0].status}"></td>
<td th:text="${category.items[0].zipcode}"></td>
<td th:text="${category.items[0].price}"></td>
</tr>
-->
This is my first web app using Spring mvc, at this point I am a bit stuck and would appreciate it if someone pointed me towards the right path thank you :D
To achieve a nested loop in Thymeleaf, simply do the following:
<th:block th:each="category : ${categorys}">
<tr th:each="item : ${category.items}">
<td th:text="${category.item.title}"></td>
<td th:text="${category.item.category.type}"></td>
<td th:text="${category.item.description}"></td>
<td th:text="${category.item.status}"></td>
<td th:text="${category.item.zipcode}"></td>
<td th:text="${category.item.price}"></td>
</tr>
</th:block>
I was able to achieve the result asked without the nested loops. by changing the parameter type to Category which is the attribute type in the entity class.
Repository:
List<Item> findByCategory(Category categoryid);
Controller :
#RequestMapping(value="/item-by-category/{id}",method= RequestMethod.GET)
public String itemByCategory(#PathVariable("id") Category categoryid, Model model){
model.addAttribute("items",irepository.findByCategory(categoryid));
return "/itemlist";
}

javax.el.PropertyNotFoundException:

I am working on Spring. I am unable to display the list items in JSP. It says: Property not found on type java.lang.String.
I have a POJO class Student:
public class Student {
private Integer age;
private String name;
private Integer id;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
}
In my controller class I fetch list of students and assign it to a List and add the list to the model attribute. Which is as follows.
#RequestMapping("/getstuds")
public String getstudents(#ModelAttribute Student student, ModelMap model){
StudentDAO studentDAO = (StudentJDBCTemplate)applicationContext.getBean("studentJDBCTemplate");
List<Student> students = studentDAO.listStudents();
model.addAttribute("studlist",students);
System.out.println(students.iterator().next().getName());
return "showstuds";
}
showstuds.jsp
<table>
<c:forEach var="stud" items="${studlist} }">
<tr><td>${stud.Name}</td></tr>
</c:forEach>
</table>
I get the following exception:
javax.el.PropertyNotFoundException: Property 'Name' not found on type com.spring.mvc.Student
your variable name is name not Name
<tr><td>${stud.name}</td></tr>
instead of
<tr><td>${stud.Name}</td></tr>
And also remove the brace
items="${studlist}"
instead of
items="${studlist} }"

Strange behaviour of MongoDB when querying by foreign key

I am writing some test code to learn spring-data with MongoDB. I can successfully create two Documents: Person and ADocument, where ADocument contains a reference to Person.
#Document
public class Person {
#Id
private ObjectId id;
#Indexed
private String name;
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
...
#Document
public class ADocument {
#Id
private ObjectId id;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
private String title;
private String text;
#DBRef
private Person docperson;
public Person getDocperson() {
return docperson;
}
public void setDocperson(Person docperson) {
this.docperson = docperson;
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
}
The problem arises when I try to get all the 'adocuments' related to a person by using the person's ID (once the person's name is provided):
public List<ADocument> loadDocumentsByPersonName(String pname) {
Query qPerson = new Query().addCriteria(Criteria.where("name").is(pname));
qPerson.fields().include("_id");
Person pers = mongoTemplate.findOne(qPerson, Person.class);
ObjectId persId = pers.getId();
Query qDoc = new Query().addCriteria(Criteria.where("person.$id").is(persId));
System.out.println(qDoc.toString());
List<ADocument> list2 = mongoTemplate.find(qDoc, ADocument.class);
return list2;
}
Everyting works fine except that list2 is always empty (while it shouldn't).
System.out.println(qDoc.toString()) gives something like:
Query: { "person.$id" : { "$oid" : "536a0d50e4b0d0c10297f2ab"}}, Fields: null, Sort: null
If I try to issue the query above on the Mongo shell I get the following:
db.adocument.find({ "person.$id" : { "$oid" : "536a0805e4b0af174d0b5871"}})
error: {
"$err" : "Can't canonicalize query: BadValue unknown operator: $oid",
"code" : 17287
}
While if I type
db.adocument.find({ "person.$id" : ObjectId("536a0805e4b0af174d0b5871")})
I actually get a result!
I am using MongoDB 2.6.0 and Spring Data 1.4.2.
I really can't figure out what's going on... Any help is extremely appreciated!
I got it!
For some reason, I had to explicit the collection name in the Query:
List list2 = mongoTemplate.find(qDoc, ADocument.class, COLLECTION_NAME);
where COLLECTION_NAME="adocument".
As for the shell behaviour, it seems that Query.toString() does never return a correct syntax to be cut and paste for shell execution.

Categories

Resources