I`m developing an application that needs to keep some Twitter4J statuses on a MySql database.
Where can I find a place with informations to help me model the table?
You should look at the twitter4j Status interface. It has all the information relating to a status including for example:
createdAt()
getId()
User
text
The Status object that you will create can also be used to retrieve arrays of information such as:
hashtags
URLs/links
media entities
And mentions.
There is more functionality - check out the java doc here http://twitter4j.org/en/javadoc/index.html
How you implement this is obviously up to you. Twitter offers a number of APIs, more information can be found at twitter dev site under documentation.
When making your choice bare in mind that the REST API is rate limited meaning that you will only be able to make a certain number of requests for a given time period (again see docs for more info).
You also have access to the streaming API that pushes all data to your application based on factors such as keyword filters.
You can then design your database model.You could do this using standard MySQL library or if you are using java ee platform you could create and entity class like so :
package entities;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
#Table(name = "twitterstatus")
public class TwitterStatus implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "statusId")
private Long statusId;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 15)
#Column(name = "statusUserName")
private String statusUserName;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 140)
#Column(name = "statusText")
private String statusText;
#OneToMany(mappedBy = "statusId")
private List<TwitterStatusUrl> twitterStatusUrlList;
public TwitterStatus() {
}
public TwitterStatus(Long statusId) {
this.statusId = statusId;
}
public TwitterStatus(Long statusId, String statusUserName, String statusText) {
this.statusId = statusId;
this.statusUserName = statusUserName;
this.statusText = statusText;
}
public Long getStatusId() {
return statusId;
}
public void setStatusId(Long statusId) {
this.statusId = statusId;
}
public String getStatusUserName() {
return statusUserName;
}
public void setStatusUserName(String statusUserName) {
this.statusUserName = statusUserName;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(String statusText) {
this.statusText = statusText;
}
public List<TwitterStatusUrl> getTwitterStatusUrlList() {
return twitterStatusUrlList;
}
public void setTwitterStatusUrlList(List<TwitterStatusUrl> twitterStatusUrlList) {
this.twitterStatusUrlList = twitterStatusUrlList;
}
}
note: you will need to create a data-source and persistence unit (there are many tutorials online surrounding this area. An example could be this article and others that it links to - JPA java code generation).
Sorry would have included more links to useful info but am limited because I am a new user here.
Related
I have a Spring-boot application that uses JPA and Hibernate. You can find the whole code on this GitHub repository.
My question is how can I add internationalization functionality to a specific column without any foreign keys and by using JSON structure?
For example I would like to define a JPA entity like this:
#Entity
class Book {
#Id
private int id;
private Author author;
#I18n //<- this annotation is something that I am looking for
private String title;
}
and then the data in title column would be stored like the following for en and de locales:
{"en":"Cologne","de":"Köln"}
And then when the current locale is de the Köln and when the en is set as locale then Cologne fetch in the time of reading data!
Also when we store the data, the passed string is stored in the relevant property in the JSON format. For example if the locale is set to es and user passes Kolne then we have to have the following data in the DB:
{"en":"Cologne","de":"Köln","es":"Kolne"}
It is interesting for me that most of the solutions in the web for hibernate and JPA is based on an old method that we have languages and translations tables. Something like here or here.
However what I am looking for is some solutions like this one which is suggested for Laravel and store the translations exactly in the way that I explained (i.e. in a JSON object and in the same column)!
The only solution that I found and could be somehow relevant (Not 100%) is this one, however it does not working when I tried to test it and it seems does not supported anymore!
Hibernate Types project
First, you need to add the Hibernate Type project dependency.
Afterward, you could use either an HStore or a JSONB column to store the locate-specific titles:
#Entity
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
class Book {
#Id
private int id;
private Author author;
#Type(type = "jsonb")
#Column(name = "localized_titles", columnDefinition = "jsonb")
private Map<String, String> localizedTitles = new HashMap<>();
public String getLocalizedTitle(String locale) {
return localizedTitles.get(locale);
}
public String getLocalizedTitle() {
return localizedTitles.get(LocaleUtil.getDefaultLocale());
}
}
So, you can call the getLocalizedTitle and pass the current locale to get the current localized title.
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle("en");
Or, you could store the current locale in a ThreadLocal in a class called LocaleUtil:
public class LocaleUtil {
private static final ThreadLocal<String> LOCALE_HOLDER =
new ThreadLocal<>();
public static String getLocale() {
return LOCALE_HOLDER.get();
}
public static void setLocale(String locale) {
LOCALE_HOLDER.set(locale);
}
public static void reset() {
LOCALE_HOLDER.remove();
}
}
And store the current locale like this:
LocaleUtil.setLocale("en");
And, then just call the getLocalizedTitle method that takes no argument:
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle();
Check out this PostgreSQLJsonMapTest test case on GitHub for more details about using Hibernate Types to persiste Java Map as JSON column types.
After some weeks I could return back again to my olingo2 odata server project.
What I wanted to do was simpler than what I expected.
The solution has been suggested by Vlad Mihalcea is good and I appreciate it, however as I mentioned in the question I need a solution that works beside of the Olingo JPA library! However, the suggested solution has this problem that Olingo cannot handle JsonBinaryType.
Here is my suggestion for implementing internationalization beside of Olingo JPA.
Assume we have a BasicModel.java like this:
import java.io.Serializable;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import java.io.IOException;
public abstract class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
private static ObjectMapper mapper = new ObjectMapper();
#SuppressWarnings("unchecked")
protected static Map<String, String> jsonToMap(String json) {
Map<String, String> map = new HashMap<>();
try {
// convert JSON string to Map
if (json != null) {
map = (Map<String, String>) mapper.readValue(json, Map.class);
}
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
protected static String mapToJson(Map<String, String> map) {
String json = "";
try {
// convert map to JSON string
json = mapper.writeValueAsString(map);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return json;
}
protected static String getLang() {
Locale currentLocale = LocaleContextHolder.getLocale();
String[] localeStrings = (currentLocale.getLanguage().split("[-_]+"));
return localeStrings.length > 0 ? localeStrings[0] : "en";
}
}
This class provides a mechanism for us to convert JSON strings to Map and vice versa.
The code for converters had been adapted from here. For using this snippet of code we need to add this maven dependency:
<!-- Convert JSON string to Map -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
Finally, whenever in a JPA entity model we want to have i18n for a string property we only need to modify setter and getter methods slightly. For example:
import javax.persistence.*;
import java.util.Map;
import java.util.Set;
/**
* The persistent class for the actions database table.
*
*/
#Entity
#Table(name = "actions")
#NamedQuery(name = "Action.findAll", query = "SELECT a FROM Action a")
public class Action extends BaseModel {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id", unique = true, nullable = false, length = 255)
private String id;
#Column(nullable = false, length = 255)
private String name;
public Action() {
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
Map<String, String> map = jsonToMap(this.name);
return map.get(getLang());
}
public void setName(String name) {
Map<String, String> map = jsonToMap(this.name);
map.put(getLang(), name);
this.name = mapToJson(map);
}
}
I have this JPA Class, where I have 3 columns id, name and date. The Database is already filled with data, where each entry has an id.
#Data
#Entity
#Table(name = "TEST", schema = "TESTSCHEMA")
public class TestDataJpaRecord implements Serializable {
private static final long serialVersionUID = 1L;
TestDataJpaRecord(){
// default constructor
}
public TestDataJpaRecord(
String name,
Date date,
){
this.name = name;
this.date = date;
}
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "TEST_SEQUENCE")
#SequenceGenerator(
sequenceName = "TEST_SEQUENCE", allocationSize = 1,
name = "TEST_SEQUENCEx")
private Long id;
#Column(name = "NAME")
private String name;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "DATE")
private Date date;
}
I created a JPA repository for all the data.
public interface TestDataJpaRecordRepository extends JpaRepository<TestDataJpaRecord, Long> {
}
I want to get the data from the DB in a JSON format.
Here is my Rest GET Api. Here I return the data as a string just, but I want to return them as JSON.
#GetMapping(value = "data/{id}")
private ResponseEntity<?> getDataFromTheDB(#PathVariable("id") Long id) {
// get one entry form the DB
TestDataJpaRecord testDataJpaRecord =testDataJpaRecordRepository.findOne(id);
// Here I want to return a JSON instead of a String
return new ResponseEntity<>(testDataJpaRecord.toString(), HttpStatus.OK);
}
Any idea on how I could return the data as JSON and not as a string from the DB?
I would very very much appreciate any suggestion.
If you have Jackson on the classpath which you should if you have used the spring-boot-starter-web then simply:
#GetMapping(value = "data/{id}")
private ResponseEntity<TestDataJpaRecord> getDataFromTheDB(#PathVariable("id") Long id) {
TestDataJpaRecord testDataJpaRecord =testDataJpaRecordRepository.findOne(id);
return new ResponseEntity.ok(testDataJpaRecord);
}
This assumes you have annoted your controller with #RestController rather than #Controller. If not then you can either do that or, annotate your controller method with #ResponseBody.
With Spring Data's web support enabled (which it should be by default with Spring Boot) then you can also simplify as below:
#GetMapping(value = "data/{id}")
private ResponseEntity<TestDataJpaRecord>
getDataFromTheDB(#PathVariable("id") TestDataJpaRecord record) {
return new ResponseEntity.ok(record);
}
See:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web.basic.domain-class-converter
Currently, we are using MySQL as a database and we use
#Generated Value(strategy = GenerationType.IDENTITY)
It's working perfectly in certain situations we need to migrate our database to Oracle at that time it's not working properly. If anyone knows what's the actual difference is present behind this and how it's working?
Quoting Java Persistence/Identity and Sequencing:
Identity sequencing uses special IDENTITY columns in the database to allow the database to automatically assign an id to the object when its row is inserted. Identity columns are supported in many databases, such as MySQL, DB2, SQL Server, Sybase and Postgres. Oracle does not support IDENTITY columns but they can be simulated through using sequence objects and triggers.
so I prefer to use SEQUENCE instead
Sequence objects use special database objects to generate ids. Sequence objects are only supported in some databases, such as Oracle, DB2, and Postgres. Usually, a SEQUENCE object has a name, an INCREMENT, and other database object settings. Each time the .NEXTVAL is selected the sequence is incremented by the INCREMENT.
Example :
#Entity
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="EMP_SEQ")
#SequenceGenerator(name="EMP_SEQ", sequenceName="EMP_SEQ", allocationSize=100)
private long id;
...
}
How could it "work properly" (you don't define basic info like what you mean by that) with Oracle ? I don't see the relevance of AUTO to your question - that simply lets an implementation choose what it wants to use.
"IDENTITY" (as per JPA javadocs and spec - what you should be referring to) means autoincrement. There is no such concept in Oracle, yet there is in MySQL, SQLServer and a few others. I would expect any decent JPA implementation to flag an error when even trying such a thing.
Oracle would allow "SEQUENCE", or "TABLE" strategies to be used however
Im using JPA and Oracle 11g, the solution that worked for me is the following
package com.example.springsocial.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(name = "rol", uniqueConstraints = {
#UniqueConstraint(columnNames = "name")
})
public class Rol {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="rol_sequence")
#SequenceGenerator(name="rol_sequence", sequenceName="rol_sequence", allocationSize=100)
private Long id;
#Column(nullable = false)
private String name;
private Date createdAt;
#Column(nullable = true)
private Date updatedAt;
#Column(nullable = true)
private Integer createdBy;
#Column(nullable = true)
private Integer updatedBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
public Integer getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Integer updatedBy) {
this.updatedBy = updatedBy;
}
}
How to bind my new object user with an role object in my spring boot application when I receive an request post with a json/application that has all data for the new user?
What is the best approach (inform the role in the json)? If yes, how must be the json concerned the role information?
I will try to explain myself. First, I am sorry, I am not a native English speaker.
I want to create a new object user mapping the json received from a HTTP request post. The problem is that I have an internal object from my model named role. Roles are always either a common or an admin. Then I want to reference an already instantiated role object.
So, I want to know how to indicate the role from my user. You should consider that the model can not be modified because some internal team restriction. I don't know if the correct restful approach is send the role information in the json. How would you do this task?
My code
Class Controller
#RestController
public class UserController {
#RequestMapping(method=RequestMethod.POST, value="/users", produces = "application/json")
public #ResponseBody ResponseEntity<EntityUser> create(#Validated #RequestBody EntityUser user)
{
return new ResponseEntity<>(userService.add(user), HttpStatus.CREATED);
}
}
The Service class
#Service
public class UserService {
public EntityUser add(EntityUser user)
{
if (userRepository.findByName(user.getName()) == null)
return userRepository.save(user);
return null;
}
}
My plain object EntityUser (the json is mapped to it).
#Entity
public class EntityUser {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="user_sequence")
private long id;
#Column(name = "name")
#NotNull
private String name;
#Column(name = "email", unique = true)
#NotNull
private String email;
#ManyToOne(fetch=FetchType.EAGER)
// #NotNull
private EntityRole role;
...
}
and finally my EntityRole class
#Entity
public class EntityRole {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="role_sequence")
private long id;
#NotNull
private String label;
#NotNull
private String permission;
...
}
I'm working on a project with Spring Data JPA. I have a table in the database as my_query.
I want to create a method which takes a string as a parameter, and then execute it as a query in the database.
Method:
executeMyQuery(queryString)
As example, when I pass
queryString= "SELECT * FROM my_query"
then it should run that query in DB level.
The repository class is as follows.
public interface MyQueryRepository extends JpaRepository<MyQuery, Long>{
public MyQuery findById(long id);
#Modifying(clearAutomatically = true)
#Transactional
#Query(value = "?1", nativeQuery = true)
public void executeMyQuery(String query);
}
However, it didn't work as I expected. It gives the following error.
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''select * from my_query;'' at line 1
Is there any other way, that I could achieve this goal?
The only part of it you can parameterise are values used in WHERE clause. Consider this sample from official doc:
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
Using EntityManager you can achieve this .
Suppose your entity class is like bellow:
import javax.persistence.*;
import java.math.BigDecimal;
#Entity
#Table(name = "USER_INFO_TEST")
public class UserInfoTest {
private int id;
private String name;
private String rollNo;
public UserInfoTest() {
}
public UserInfoTest(int id, String name) {
this.id = id;
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", nullable = false, precision = 0)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "roll_no", nullable = true)
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
}
And your query is "select id, name from users where roll_no = 1001".
Here query will return an object with id and a name column. Your Response class is like below:
Your Response class is like:
public class UserObject{
int id;
String name;
String rollNo;
public UserObject(Object[] columns) {
this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
this.name = (String) columns[1];
}
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 getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
}
here UserObject constructor will get an Object Array and set data with the object.
public UserObject(Object[] columns) {
this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
this.name = (String) columns[1];
}
Your query executing function is like bellow :
public UserObject getUserByRoll(EntityManager entityManager,String rollNo) {
String queryStr = "select id,name from users where roll_no = ?1";
try {
Query query = entityManager.createNativeQuery(queryStr);
query.setParameter(1, rollNo);
return new UserObject((Object[]) query.getSingleResult());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
Here you have to import bellow packages:
import javax.persistence.Query;
import javax.persistence.EntityManager;
Now your main class, you have to call this function. First get EntityManager and call this getUserByRoll(EntityManager entityManager,String rollNo) function. Calling procedure is given below:
Here is the Imports
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
get EntityManager from this way:
#PersistenceContext
private EntityManager entityManager;
UserObject userObject = getUserByRoll(entityManager,"1001");
Now you have data in this userObject.
Note:
query.getSingleResult() return a object array. You have to maintain the column position and data type with query column position.
select id,name from users where roll_no = 1001
query return a array and it's [0] --> id and 1 -> name.
More info visit this thread .
There is no special support for this. But what you can do is create a custom method with a String parameter and in your implementation get the EntityManager injected and execute it.
Possibly helpful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
How to access entity manager with spring boot and spring data
Note: I would reconsider if what you are trying to do is a good idea because it bleeds implementation details of the repository into the rest of the application.
if you want to add custom query you should add #Param
#Query("from employee where name=:name")
employee findByName(#Param("name)String name);
}
this query will select unique record with match name.this will work
Thank you #ilya. Is there an alternative approach to achieve this task using Spring Data JPA? Without #Query annotation?
I just want to act on this part. yes there is a way you can go about it without using the #query annotation. what you need is to define a derived query from your interface that implements the JPA repository instance.
then from your repository instance you will be exposed to all the methods that allow CRUD operations on your database such as
interface UserRepository extends CrudRepository<User, Long> {
long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
with these methods spring data will understand what you are trying to archieve and implement them accordingly.
Also put in mind that the basic CRUD operations are provided from the base class definition and you do not need to re define them. for instance this is the JPARepository class as defined by spring so extending it gives you all the methods.
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
}
For more current information check out the documentation at https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Based on #jelies answer, I am using the following approach
You can create another interface for your custom methods (as example MyQueryCustom) and then implement it as follows.
public class MyQueryRepositoryImpl implements MyQueryRepositoryCustom {
#PersistenceContext
private EntityManager entityManager;
public int executeQuery(String query) {
return entityManager.createNativeQuery(query).executeUpdate();
}
}
This will execute a custom query.