SpringHibernate - set up mysql tables for a Simple Blogging app - mysql

I am creating a simple blogging application using Spring Boot by following ( an incomplete )tutorial at: http://www.nakov.com/blog/2016/08/05/creating-a-blog-system-with-spring-mvc-thymeleaf-jpa-and-mysql/#comment-406107.
The model entity classes are as follows, Post and User:
First the code for Post:
#Entity
#Table(name="posts")
public class Post {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#Column(nullable=false, length = 300)
private String title;
#Lob #Column(nullable=false)
private String body;
#ManyToOne(optional=false, fetch=FetchType.LAZY)
private User author;
#Column(nullable = false)
private Date date = new Date();
public Post() {
}
public Post(long id, String title, String body, User author) {
this.id = id;
this.title = title;
this.body = body;
this.author = author;
}
And this is the code for User:
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(nullable=false, length=30, unique=true)
private String username;
#Column(length=60)
private String passwordHash;
#Column(length=100)
private String fullName;
#OneToMany(mappedBy="author")
private Set<Post> posts = new HashSet<>();
public User() {
}
public User(Long id, String username, String fullName) {
this.id = id;
this.username = username;
this.fullName = fullName;
}
Note that I have omitted package, imports, and getter/setters for convenience.
Just in case, I include my application.properties file:
spring.thymeleaf.cache = false
server.ssl.enabled=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/blog_db
spring.datasource.username=root
spring.datasource.password=somepassword
#Configure Hibernate DDL mode: create/update
spring.jpa.properties.hibernmate.hbm2ddl.auto=update
I want to create a corresponding database for my code to hook up to using mysql community server ( the workbench, to be more specific ) and since I'm completely unfamiliar with mysql I'm not having any success. ( The tut author failed to provide db script so I'm trying to recreate it ).
I'm hoping someone would be willing to help me out with the mysql database scripting.

Make sure you have the needed dependencies in your pom.xml
<!-- JPA Data (We are going to use Repositories, Entities, Hibernate, etc...) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Use MySQL Connector-J -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
and don't forget to add this line to your application.properties.Once you have run your project replace create to update or none this will avoid the inherent drop of a table to create a new one.
spring.jpa.hibernate.ddl-auto=create
If you have any questions the following link will be a good start
https://spring.io/guides/gs/accessing-data-mysql/

Related

Java JPA: Unable to find all records between 2 LocalDates

Hello i am new to JPA and i have created an application where i want to find all the users posts that where made from the start of the month to the last day of the month.My model only contains the date the post has been created at as you can see below.I want to retrieve all the posts that where created in that specific month.I have a method below where i am using LocalDate(threetenbp dependency) to provide that(not sure if this is correct).
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate createdAt;
private LocalDate modifiedAt;
#NotBlank(message = "Post Title is required")
private String title;
#Basic(fetch = FetchType.LAZY)
private String image;
#NotBlank(message = "Post Content is required")
private String content;
#OneToMany(cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "POST_TAG", joinColumns = {#JoinColumn(name = "post_id")},
inverseJoinColumns = {#JoinColumn(name = "tag_id")})
private Set<Tag> tags = new HashSet<>();```
public List<Post> doSomething() {
// something that should execute on 1st day every month # 00:00
LocalDate now = LocalDate.now();
LocalDate start = now.withDayOfMonth(1);
LocalDate end = now.withDayOfMonth(now.lengthOfMonth());
List<Post> postsThisMonth = postRepository.findAllBetweenCreatedAtandend(start, end);
return postsThisMonth;
}
As you can see in this method i am providing the current date, and the first day of the month and the last day of the month and then i call the repository with those values.
#Repository
public interface PostRepository extends CrudRepository<Post, Long> {
List<Post> findAllBetweenCreatedAtandend(LocalDate start, LocalDate end);
}
Problem is the repository method is not working.I am getting errors like
(org.threeten.bp.LocalDate,org.threeten.bp.LocalDate)! No property No property findAllBetweenCreatedAtandend found for type Post!
Please help me create a working method for my repository that returns the posts between the 2 dates.
Thank you !
The correct method name would be findAllByCreatedAtBetween
Also, I'm not sure what 'LocalDate(threetenbp dependency)' is, but JPA only works with parameter types it understands how to map to database types. Adding support for custom types as query parameters is a pain in JPA, and I'm not even entirely sure it's possible with Spring Data on top.
the problem is that i won't have the methods provided here LocalDate start = now.withDayOfMonth(1); LocalDate end = now.withDayOfMonth(now.lengthOfMonth());
You can use TemporalAdjusters.firstDayOfMonth() and TemporalAdjusters.lastDayOfMonth()

spring boot mongodb #dbref cascade not working

I am struggling with Spring Boot MongoDB cascade operations on referenced objects. Below are MongoDB document schema classes.
== Post
#Getter
#Setter
#Document(collection="Post") // (1)
public class Post {
#Id
private String _id;
#Indexed(unique = true)
private Long id;
private String title;
private String body;
private Date createdDate;
#DBRef(db = "User", lazy = true)
private User user;
#DBRef(db = "Tag", lazy = true)
private Collection<Tag> tags;
== User
#Getter
#Setter
#Document(collection="User") // (1)
public class User {
#Id //(2)
private String _id;
#Indexed(unique = true)
private Long id;
#Indexed(unique=true) // (3)
private String username;
private String password;
private String email;
private String fullname;
private String role;
}
== Tag
#Getter
#Setter
#Document(collection="Tag")
public class Tag {
#Id
private String _id;
#Indexed(unique = true)
private Long mid;
private String body;
private Date createdDate;
#DBRef(db = "User", lazy = true)
private User user;
}
But #DBRef annotation does not work at all. It throws the following exception.
2019-03-01 14:54:10.411 ERROR 5756 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.mapping.MappingException: Cannot create a reference to an object with a NULL id.] with root cause
org.springframework.data.mapping.MappingException: Cannot create a reference to an object with a NULL id.
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createDBRef(MappingMongoConverter.java:975) ~[spring-data-mongodb-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:597) ~[spring-data-mongodb-2.1.4.RELEASE.jar:2.1.4.RELEASE]
When the json file is imported into MongoDB schema, the above error is shown. I found some reference site with googling which said to generate new event source using CascadingMongoEventListener class and user-defined #CascadeSave annotation. But I think there are another solutions with some cascade annotations. Any idea,please.
Mongo doesn't support the relationship between documents. Due to this cascade operation doesn't support in spring data mongo. you can do it in two manners.
1) Make your own cascade handler(best way to do is to use spring event publisher) But it can also be done using custom handler without spring event see here.
2) Make an explicit call to referenced DB for operation.
Take a look at RelMongo which is a framework built on top of Spring Data and which make possible cascading, fetching.. and even lookups which are not possible with DBRefs

With Spring Boot, how to post JSON object that represents an entity whose member is another entity

(***Edited*:**I am looking for the JSON representation of the solution provided here: Spring REST multiple #RequestBody parameters, possible?)
I have the following entity Account which has a member variable of another entity called Customer
#Entity
public class Account {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id=0;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
...
}
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id=0;
private String customerId;
public Customer(){}
public Customer(String customerId){
this.customerId = customerId;
}
public long getId(){
return id;
}
public String getCustomerId(){
return customerId;
}
public void setCustomerId(String customerId){
this.customerId = customerId;
}
}
I need to post a JSON object representation of an Account. Here is the Controller method:
#Autowired
private AccountRepository accounts;
#RequestMapping(value="/accounts/account",method=RequestMethod.POST)
public #ResponseBody Account addAccount(#RequestBody Account account){
return accounts.save(account);
}
AccountRepository is an interface that extends CrudRepository
I have an existing customer with the URI http://localhost:8084/customers/customer/1
I have attempted to post the following JSON objects and received a 400 Bad Request response.
{"customer":"1"}
{"customer":"http://localhost:8084/customers/customer/1"}
{"customer":{"href":"http://localhost:8084/customers/customer/1"}}
Just to make sure that an Account can be created if correct data is received, I modified the controller method as per the following code, which created the account when I post to http://localhost:8084/accounts/account
#RequestMapping(value="/accounts/account",method=RequestMethod.POST)
public #ResponseBody Account addAccount() throws Exception{
Customer customer = customers.findOne(1);
Account account = new Account();
account.setCustomer(customer);
return accounts.save(account);
}
So my question is, how do I format a JSON object so as to Create an Entity whose member is an existing Entity?
I found out that the correct format is to provide the URI of the referenced entity, i.e in this case it should be
{"customer":"http://localhost:8084/customers/customer/1"}
However, this only worked after I added the data-rest dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>{spri}</version>
</dependency>
Without this dependency, the request fails with a JsonMappingException

Spring data jpa: findBy property hangs on "Starting beans in phase 2147483647" in Junit test

I'm having a problem in my junit test while accessing my spring data jpa repository.
I'm using the findByProperty functionality. But it hangs while accessing it.
My Entity:
#Entity
#Table(name = "TC_ORDER")
public class Order extends AbstractCatalog{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ORDER_SID")
private Long id;
}
My Abstractcatalog:
#MappedSuperclass
public abstract class AbstractCatalog {
#Column(unique = true, nullable = false, name = "CODE",updatable=false)
private String code;
public void setCode(final String code) {
this.code = code;
}
public String getCode() {
return this.code;
}
}
Spring data jpa repository:
public interface OrderRepository extends AbstractCatalogRepository<Order> {
}
AbstractCatalogRepository:
#NoRepositoryBean
public interface AbstractCatalogRepository<T extends AbstractCatalog> extends
CustomRepository<T, Serializable> {
T findByCode(String code);
}
The junit test:
#Inject
private OrderRepository orderRepository;
#Test
public void orderCatalogisComplete() throws Exception {
Assert.assertNotNull(orderRepository); // OK
Assert.assertEquals(18,orderRepository.count()); //OK
}
#Test
public void searchForSL1InDb(){
Order sl1 = orderRepository.findByCode("SL-1"); // HANGS HERE
Assert.assertNotNull(sl1);
}
}
This is the relevant resulting logging:
...preceding spring integration logging (also used in my project)...
13:49:19.828 INFO o.s.i.m.IntegrationMBeanExporter start 357 - started org.springframework.integration.monitor.IntegrationMBeanExporter#1202f4d
13:49:19.828 INFO o.s.c.s.DefaultLifecycleProcessor start 334 - Starting beans in phase 2147483647
And there it hangs..
I've run into a similar issue, if you are logging elsewhere, check your other log location as there might be another message from a component that makes the build hang - in my case it was cobertura.
add below given dependency in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

#JsonIgnore and #JsonBackReference are being Ignored

I'm working with RestEasy, Jboss 7 and EJB 3.1. I'm creating a RESTful web service that returns data in JSON format.
The problem is that I have a #ManyToOne relationship on one of my entities which causes an infinite recursion during serialization. I tried using Jackson's #JsonIgnore and #JsonBackReference annotations to fix the problem but it seems as if they are being totally ignored and the infinite recursion is still occurring.
This is my User Class:
class User {
private String userId;
private Role role;
#Id
#Column(name = "\"UserId\"", unique = true, nullable = false, length = 30)
public String getUserId() {
return this.UserId;
}
public void setUserId(String UserId) {
this.UserId = UserId;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "\"RoleId\"", nullable = false)
//I have tried #JsonIgnore without #JsonBackReference
#JsonIgnore
//I have tried #JsonBackReference without #JsonIgnore
//Also I have tried #JsonBackReference and #JsonIgnore together
#JsonBackReference("role-User")
public Role getRole() {
return this.role;
}
}
This is a part of my Role Class:
#JsonManagedReference("role-User")
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "role")
public Set<User> getUsers() {
return this.users;
}
I have read somewhere that I should register Jackson with my application to be able to use regular Jaxb annotation so I created a class
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
public JacksonContextResolver() {
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
mapper.getDeserializationConfig().setAnnotationIntrospector(
introspector);
mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
}
public ObjectMapper getContext(Class<?> objectType) {
return objectMapper;
}
}
The problem with the above being that JaxbAnnotationIntrospector() is deprecated.
Please:
Do you have any idea why the Jackson annotations are being ignored?
How can I use the regular JAXB XML annotations instead of Jackson's?
What can I use instead of JaxbAnnotationIntrospector()?
An answer to any of these question is appreciated, thanks.
Update:
For now I have excluded resteasy-jackson-provider using jboss-deployment-structure.xml and I am using Jettison instead. I still want to know how could I use Jackson!
The problem here seems to be related to using Set<User> instead of List<User>. I had exactly the same problem and changing from Set<User> to List<User> fixed this, otherwise I always got Infinite recursion error from Jackson. I don't know if this is really a bug in Jackson or do you have to provide some other annotations etc. when using Set.
use import com.fasterxml.jackson.annotation.JsonBackReference; instead of import org.codehaus.jackson.annotate.JsonBackReference;.
It was the problem for me.
I had this problem and got the same code to work by updating the version of the Jackson library in my build (pom.xml) from 1.8.x to 1.9.13. If you are using maven, edit your pom.xml to contain:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
Documentation doesn't help, but it seems that back references for Sets were not supported in the 1.8.x versions.
Look, I have something similar to you and is working just fine for me...
#JsonBackReference("promotion-travel")
#ManyToOne(cascade = CascadeType.ALL)
#JoinTable(name="PROMOTION_TRAVEL_REL",
joinColumns = #JoinColumn(name="TRAVEL_ID"),
inverseJoinColumns = #JoinColumn(name="PROMOTION_ID")
)
public Promotion getPromotion(){...
And this is what I have on Entity1
#JsonManagedReference("promotion-travel")
#OneToMany(mappedBy="promotion")
public List<Travel> getTravelList(){...
I don't know if moving the annotation to the top will change anything, but that's the only thing that I can see...
Cheers,
I had a similar problem where my getter function was not named based on the field name, so the json parsing was still happening for the getter. Changing the getter name solved the issue.
i'm using spring 4.0.1 , hibernate 4.3.5 ,jackson 1.9.2 and STS IDE
i had the same exception but solved by annotating the setter by #Transient
idont know why but it works fine
This is my entity classes
User.class
//i get that suggestion from some sites
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
#Entity
#Table(name = "user", catalog = "someSchema")
public class User implements java.io.Serializable {
private String name;
private String password;
private String username;
private Set<Telephone> telephones = new HashSet<Telephone>(0);
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Telephone> getTelephones() {
return this.telephones;
}
public void setTelephones(Set<Telephone> telephones) {
this.telephones = telephones;
}
}
Telephone.class
#Entity
#Table(name = "telephone", catalog = "someSchema")
public class Telephone implements java.io.Serializable {
private User user;
private String telephone;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
public User getUser() {
return this.user;
}
#Transient
public void setUser(User user) {
this.user = user;
}
}
concerning registering jackson to my application, i used xml config
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean
class="web.jsonConverters.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
and mapper class
public class HibernateAwareObjectMapper extends ObjectMapper {
public HibernateAwareObjectMapper() {
Hibernate4Module hm = new Hibernate4Module();
registerModule(hm);
}
}