Suppose, that we have such tables:
Table Users
iduser | password
Table Marks
id | iduser | mark | idtest
Table Tests
idtest | title
Query looks like this:
#GET
#Path("/{id}/marks")
#Produces(MediaType.APPLICATION_JSON)
public Object funkcja(#PathParam("id") Integer iduser) {
Query query = em.createQuery("select m,t from Marks m, Tests t where m.idusers=:iduser and m.idtest = t.idtests");
query.setParameter("iduser", id);
List<Object> results = (List<Object>)query.getResultList();
return results;
}
I have entity classes:
Marks , Users, Tests
What I should to do in order to join tables and send JSON type on web service and how to convert JSON to entity class because I would like to show in TableView.
Perhaps there are other simple ways?
Maybe map or JsonObject?
You seem to have multiple questions here; I think you need to break these down into separate questions.
For the "main" question, which is about JPA and how to join the entities, I would do that at the entity level, not at the query level. I.e. I think I would have entity classes like:
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="Tests")
public class Test {
#Id
#Column(name="idtest")
private int id ;
private String title ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public boolean equals(Object other) {
if (other instanceof Test) {
return Objects.equals(title, ((Test)other).title);
} else return false ;
}
#Override
public int hashCode() {
return Objects.hash(title);
}
}
and then the Mark entity can use a #ManyToOne annotation to reference the actual Test object (not its id):
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="Marks")
public class Mark {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id ;
#ManyToOne
#JoinColumn(name="idtest")
private Test test ;
// You probably don't want a reference to User here, as the User class
// encapsulates the password, which you don't want to throw back and
// forward across the network unnecessarily. But if the User class
// instead had a user name etc you wanted, you could use the same
// #ManyToOne technique to reference a User object here if you needed.
#Column(name="iduser")
private int userId ;
private int mark ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public int getMark() {
return mark;
}
public void setMark(int mark) {
this.mark = mark;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Mark) {
Mark other = (Mark)obj ;
return Objects.equals(userId, other.userId)
&& Objects.equals(test, other.test)
&& mark == other.mark ;
} else return false ;
}
#Override
public int hashCode() {
return Objects.hash(userId, test, mark);
}
}
Now your query looks like
TypedQuery<Mark> query = em.createQuery("select m from Mark m where m.userId=:userid");
query.setParameter("userid", iduser);
List<Mark> results = query.getResultList();
and the Mark instances in the list already have all the data you need:
for (Mark mark : results) {
System.out.println(mark.getTest().getTitle() + ": " + mark.getMark());
}
For the remaining questions:
Assuming you have a server set up with a JAX-RS implementation (e.g. Jersey) the code snippet you showed (modified with the new query) should generate JSON output. (You can use a developer tool such as Firefox REST client to view the JSON output by specifying the appropriate URL and request headers, and viewing the response.)
On the client (JavaFX) side you can use Jersey's client library (or maybe Apache HttpComponent library) to create the web requests easily, and a library such as GSON or Jackson for mapping the JSON content you get back to a Java object for display in the TableView.
I recommend trying this and asking specific questions about the remaining pieces if you get stuck.
Related
i need to update tow columns inside my table (Job this table is joint with two other tables employees and job-history)one of them is the primary key, but i get error, if someone can help.
package com.touati.org.model;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.List;
/**
* The persistent class for the jobs database table.
*
*/
#Entity
#Table(name="jobs")
#NamedQuery(name="Job.findAll", query="SELECT j FROM Job j")
public class Job implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="JOB_ID")
private String jobId;
#Column(name="JOB_TITLE")
private String jobTitle;
#Column(name="MAX_SALARY")
private BigDecimal maxSalary;
#Column(name="MIN_SALARY")
private BigDecimal minSalary;
//bi-directional many-to-one association to Employee
#OneToMany(mappedBy="job")
private List<Employee> employees;
//bi-directional many-to-one association to JobHistory
#OneToMany(mappedBy="job")
private List<JobHistory> jobHistories;
public Job() {
}
public String getJobId() {
return this.jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobTitle() {
return this.jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public BigDecimal getMaxSalary() {
return this.maxSalary;
}
public void setMaxSalary(BigDecimal maxSalary) {
this.maxSalary = maxSalary;
}
public BigDecimal getMinSalary() {
return this.minSalary;
}
public void setMinSalary(BigDecimal minSalary) {
this.minSalary = minSalary;
}
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Employee addEmployee(Employee employee) {
getEmployees().add(employee);
employee.setJob(this);
return employee;
}
public Employee removeEmployee(Employee employee) {
getEmployees().remove(employee);
employee.setJob(null);
return employee;
}
public List<JobHistory> getJobHistories() {
return this.jobHistories;
}
public void setJobHistories(List<JobHistory> jobHistories) {
this.jobHistories = jobHistories;
}
public JobHistory addJobHistory(JobHistory jobHistory) {
getJobHistories().add(jobHistory);
jobHistory.setJob(this);
return jobHistory;
}
public JobHistory removeJobHistory(JobHistory jobHistory) {
getJobHistories().remove(jobHistory);
jobHistory.setJob(null);
return jobHistory;
}
}
my controller: here when i try to look for all job in the data base it works fine, also if i try to update juste the title of the job it works fine to but in case that i try to set a new primary key for the job table it gives me error here my controller.
package com.touati.org.model;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
#Controller // This means that this class is a Controller
#RequestMapping(path="/project") // This means URL's start with /demo (after Application path)
public class MainController {
#GetMapping(path="/job")
public #ResponseBody Iterable<Job> getAllJob() {
// This returns a JSON or XML with the users
return jobRepository.findAll();
}
#GetMapping(path="/job/{jobId}")
public #ResponseBody String getJob(#PathVariable String jobId) {
Job job = jobRepository.findOne(jobId);
try {
job.setJobTitle("manager");
job.setJobId("test1");
jobRepository.save(job);
}
catch (Exception ex) {
return "Error updating the job: " + ex.toString();
}
return "Job succesfully updated!";
}
}
i got this error,
Error updating the user: org.springframework.orm.jpa.JpaSystemException: identifier of an instance of com.touati.org.model.Job was altered from test to test1; nested exception is org.hibernate.HibernateException: identifier of an instance of com.touati.org.model.Job was altered from test to test1
Thank you for your help.
Primary key should never be changed. If you need to change primary key it means your design is bad. If you need to change JOB_ID often then create another column for your primary key like ID. Another possibility is to copy all attributes and create new record with new JOB_ID and then remove old one.
I am getting error "Cannot create TypedQuery for query with more than one return using requested result type"
I tried with all columns value returning. That time the application hangs. I need to get list of Client, in arraylist. Please help, I am new to JPA.
#Override
public ArrayList<Client> findAllClients() {
EntityManager entity = this.emf.createEntityManager();
List<Client> clients = entity.createQuery("select clientID,clientName from Client", Client.class).getResultList();
return (ArrayList<Client>) clients;
}
Client class is
package com.springmaven.models;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="tblclient")
public class Client {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY) #Column(name="ntClientID")
private Long clientId;
#Column(name="vcClientName")
private String clientName;
#Column(name="vcLocation")
private String location;
#Column(name="ofstTimeZone")
private Date timeZone;
#Column(name="vcCommunicationMode")
private String communicationMode;
#Column(name="vcContact")
private String contact;
#OneToMany(targetEntity=Project.class,mappedBy="client",
cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Set<Project> projects = new HashSet<Project>();
public Set<Project> getProjects() {
return projects;
}
public void setProjects(Set<Project> projects) {
this.projects = projects;
}
public Long getClientId() {
return clientId;
}
public void setClientId(Long clientId) {
this.clientId = clientId;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Date getTimeZone() {
return timeZone;
}
public void setTimeZone(Date timeZone) {
this.timeZone = timeZone;
}
public String getCommunicationMode() {
return communicationMode;
}
public void setCommunicationMode(String communicationMode) {
this.communicationMode = communicationMode;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public Client(){
}
}
Usually on Hibernate you simply make selects of an specific entity, not necessarily defining what columns you want. Something like this:
List<Client> clients = entity.createQuery("select c from Client c", Client.class).getResultList();
You are getting the TypedQuery error because the EntityManager is waiting for a collection of Clients, but instead you are selecting two specific columns of it, which will make Hibernate unable to cast the results as a Client entity.
So in your case, use the query given above and everything should work fine.
You can cast to your result in (List< clients >)
List<Client> clients = (List<Client>) entity.createQuery("select clientID,clientName from Client", Client.class).getResultList();
That is a projection query on the "client" thay only return clientID and clientName, instead of loading the full object to memory. This approach can allow to reduce network traffic to the database server and save memory.
So, you can use the next one:
List<Object[]> results =
entity.createQuery("select clientID, clientName from Client").getResultList();
This result set contains a List of Object arrays and each array represents one set of properties, in this case clientID and clientName. Now you can retrieved this:
Object[] o = results.get(0); // for first element!
Long id = (Long) o[0]; // choose the correct type!
String name = (String) o[1];
In my spring web service I am accessing a my sql database with JPA+Hibernate. When I changed my database schema in the database, those changes are not reflecting from my web service.
In more detail I have added a new column formcategoryid to applicationforms table and it is added to JPA annotated class as a field. Now when I execute the query
SELECT x.formid,x.formcategoryid,x.formname FROM com.business.objects.ApplicationForms AS x WHERE x.adminroleid LIKE '3'
It gives the exception,
Caused by: org.hibernate.QueryException: could not resolve property: formcategoryid of: com.business.objects.ApplicationForms
Any idea on this?
UPDATE
My ApplicationForms class is like
package com.business.objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "applicationforms")
public class ApplicationForms {
#Id
#GeneratedValue
private int formid;
private int formcategoryid;
private int adminroleid;
private String formname;
.
.
public int getFormid() {
return formid;
}
public void setFormid(int formid) {
this.formid = formid;
}
public int getFormcategoryid() {
return formcategoryid;
}
public void setFormcategoryid(int formcategoryid) {
this.formcategoryid = formcategoryid;
}
public int getAdminroleid() {
return adminroleid;
}
public void setAdminroleid(int adminroleid) {
this.adminroleid = adminroleid;
}
public String getFormname() {
return formname;
}
public void setFormname(String formname) {
this.formname = formname;
}
}
There is a little problem in replying on ajax requests. Initially, I have simplest restful service, based on spring boot MVC.
model:
import javax.persistence.*;
import java.util.*;
#Entity
#Table(name = "testmodel")
public class TestModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)//Postgresql sequence generator
private long id;
#Column(name = "name")
private String name;
#Column(name = "content")
private String content;
//Constructor
public TestModel()
{
}
//Id getter
public long getId()
{
return this.id;
}
//Name getter-setter
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name = name;
}
//Content getter-setter
public String getContent()
{
return this.content;
}
public void setContent(String content)
{
this.content = content;
}
}
DAO for model:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/")
public class TestController
{
#Autowired
private TetsModelDAO testmodel;
#RequestMapping("/name")
public List<TestModel> getDatasetsByNameEntry(#RequestParam("entry") String entry)
{
return testmodel.fetchByNameEntry("%"+entry+"%");
}
}
Client-side ajax request:
$.ajax(
{
url : "/name?entry=", //get all records
method: "GET"
})
This example works perfectly - stringified reply looks like standart json structure:
{"id":"1", "name":"John", "content":"blablabla1"}
{"id":"2", "name":"Sam", "content":"blablabla2"}
{"id":"3", "name":"Ken", "content":"blablabla3"}
However, when I tried to define fileds in JPQL query explicitly (fetch, say, only id and name fields), I get wrong result in reply.
DAO with modified query (other code without changes):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.*;
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT s.id, s.name FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestModel> fetchByNameEntry(#Param("entry") String entry);
}
In this case reply looks like this:
1, John, 2, Sam, 3, Ken
How to resolve this problem gracefully (without creating "helper classes")?
You can return DTO directly from Repository:
public interface TetsModelDAO extends JpaRepository<Samples, Long>
{
#Query("SELECT new mypackage.TestDto(s.id, s.name) FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name")
List<TestDto> fetchByNameEntry(#Param("entry") String entry);
}
where TestDto contains only required fields:
package mypackage;
public class TestDto {
private final long id;
private final String name;
public TestDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
Your query doesn't return instances of TestModel. It returns arrays of objects (i.e. a List<Object[]>), each array containing the ID and the name of a found TestModel. The correct query is
SELECT s FROM TestModel s WHERE LOWER(s.name) LIKE LOWER(:entry) ORDER BY s.name
You'd better implement automated tests to check that your DAO queries return what they should.
I want to use the PostgreSQL uuid type for objects' primary keys.
For that I've created a converter (implementing the Converter interface).
Bellow is the relevant code:
#Override
public void initialize(DatabaseMapping mapping, Session session) {
final DatabaseField field;
if (mapping instanceof DirectCollectionMapping) {
field = ((DirectCollectionMapping) mapping).getDirectField();
} else {
field = mapping.getField();
}
field.setSqlType(Types.OTHER);
field.setTypeName("uuid");
field.setColumnDefinition("UUID");
}
Then I've annotated the relevant entity X with the bellow annotations:
#Converter(name="uuidConverter",converterCalss=UUIDConverter.class)
#Convert("uuidConverter")
#Id
public UUID getId()
{
return id;
}
The problem is that I have another class (Y) which has the following definition:
#ManyToOne(targetEntity = X.class)
#JoinColumn(name = "x_id")
public X getX();
Although EclipseLink created the tables as expected it sends a string to the database when trying to insert objects of type Y.
Postgres returns the following error message:
column "id" is of type uuid but expression is of type character varying at character
Any solutions / work around will be appreciated.
I had the same issue with EclipseLink JPA + Postgresql + UUID as primary key.
To solve it, I've merged codes from Github and below link:
https://forums.oracle.com/forums/thread.jspa?messageID=4584157
The below code for UUIDConverter worked for me, though the code surely isn't the best.
public void initialize(DatabaseMapping ARGMapping, Session ARGSession)
{
final DatabaseField Field;
if (ARGMapping instanceof DirectCollectionMapping)
{
Field = ((DirectCollectionMapping) ARGMapping).getDirectField();
}
else
{
Field = ARGMapping.getField();
}
Field.setSqlType(Types.OTHER);
Field.setTypeName("uuid");
Field.setColumnDefinition("UUID");
for (DatabaseMapping m : ARGMapping.getDescriptor().getMappings())
{
assert OneToOneMapping.class.isAssignableFrom(ManyToOneMapping.class);
if (m instanceof OneToOneMapping)
{
for (DatabaseField field : ((OneToOneMapping) m).getForeignKeyFields())
{
field.setSqlType(Types.OTHER);
field.setColumnDefinition("UUID");
field.setTypeName("uuid");
}
}
}
}
I had some issues with EclipseLink JPA 2.1 + Postgresql + UUID as primary key but I find out different solution. I adopted AttributeConverter but I faced a problem with EclipseLink implementation that I resolved with this code:
#javax.persistence.Converter(autoApply = true)
public class PostgresUuidConverter implements AttributeConverter<UUID, Object> {
#Override
public Object convertToDatabaseColumn(UUID uuid) {
PostgresUuid object = new PostgresUuid();
object.setType("uuid");
try {
if (uuid == null) {
object.setValue(null);
} else {
object.setValue(uuid.toString());
}
} catch (SQLException e) {
throw new IllegalArgumentException("Error when creating Postgres uuid", e);
}
return object;
}
#Override
public UUID convertToEntityAttribute(Object dbData) {
if (dbData instanceof String) {
return UUID.fromString(dbData.toString());
} else {
return (UUID) dbData;
}
}
}
public class PostgresUuid extends PGobject implements Comparable<Object> {
private static final long serialVersionUID = 1L;
#Override
public int compareTo(Object arg0) {
return 0;
}
}
As I exaplined in detail in this post http://blog-ungarida.rhcloud.com/persisting-uuid-in-postgresql-using-jpa-eclipselink/
Try checking what the fieldClassification of the mapping is in the initialize method. It might be getting String.class somehow, try setting it to Object.class.
or, field.setType(Object.class)
It seems there is a bug/incompatibility between EclipseLink and PostgresQL. If you just use UUID for primary keys you should be okay. But if you have a nullable UUID column, and you try to store null in it, you will get the reported error:
column "whatever" is of type uuid but expression is of type character varying
See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=538138 (log in and vote for it if you have the time!)
That bug report proved very useful to me. Specifically the link to the forum thread at:
https://www.eclipse.org/forums/index.php?t=msg&th=1073632&goto=1719530&#msg_1719530
I tried all sorts of solutions from here on SO, and elsewhere on the web. The only one that seemed to work for me was the one posted by David Wheeler there. Specifically, creating a cast from character varying to uuid in the database.
Note that you have to be user postgres to create the cast:
$ sudo su - postgres
$ psql <your database name>
# drop cast if exists (character varying as uuid);
# create or replace function uuid(_text character varying) returns uuid language sql as 'select uuid_in(_text::cstring)';
# create cast (character varying as uuid) with function uuid(character varying) as assignment;
For completeness here is the rest of what I use (in case it helps)
All my entities (that have a UUID primary key) extend a base class called EntityBase:
package com.example.entity;
import java.io.Serializable;
import java.util.UUID;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.Converter;
import com.example.converter.UUIDTypeConverter;
#MappedSuperclass
#Converter(name="uuidConverter", converterClass=UUIDTypeConverter.class)
public class EntityBase implements Serializable, Cloneable
{
private static final long serialVersionUID = 1L;
#Id
#Convert("uuidConverter")
private UUID id;
public EntityBase() {
this.id = UUID.randomUUID();
}
#Override
public int hashCode() {
return id.hashCode();
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof EntityBase)) {
return false;
}
EntityBase other = (EntityBase) obj;
return getId().equals(other.getId());
}
public UUID getId()
{
return this.id;
}
public void setId(UUID id)
{
this.id = id;
}
}
The UUID converter class looks like this:
package com.example.converter;
import java.sql.Types;
import java.util.UUID;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;
public class UUIDTypeConverter implements Converter
{
#Override
public UUID convertObjectValueToDataValue(Object objectValue, Session session)
{
return (UUID) objectValue;
}
#Override
public UUID convertDataValueToObjectValue(Object dataValue, Session session)
{
return (UUID) dataValue;
}
#Override
public boolean isMutable()
{
return true;
}
#Override
public void initialize(DatabaseMapping mapping, Session session)
{
DatabaseField field = mapping.getField();
field.setSqlType(Types.OTHER);
field.setTypeName("java.util.UUID");
field.setColumnDefinition("UUID");
}
}
If you have entities that have UUID columns that are not primary keys, you can annotate them as follows:
import org.eclipse.persistence.annotations.Convert
import org.eclipse.persistence.annotations.Converter;
#Entity
#Converter(name="uuidConverter", converterClass=UUIDTypeConverter.class)
public class BillingEvent extends EntityBase
{
#Convert("uuidConverter")
private UUID entityId;
}
Note that if that entity has other columns that use the standard javax.persistence.convert annotation, you'll need to differentiate the two Convert annotations to avoid a compile error.
For example:
import javax.persistence.Convert;
import org.eclipse.persistence.annotations.Converter;
#Entity
#Converter(name="uuidConverter", converterClass=UUIDTypeConverter.class)
public class BillingEvent extends EntityBase
{
#org.eclipse.persistence.annotations.Convert("uuidConverter")
private UUID entityId;
#Convert(converter = JSR310InstantTypeConverter.class)
private Instant createdOn;
}
I hope this saves others some time. Good luck!
Universal UUIDConverter for EclipseLink (not only PostgreSQL)
Code:
import java.nio.ByteBuffer;
import java.util.UUID;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;
public class UUIDConverter implements Converter {
private Boolean isUUIDasByteArray = true;
#Override
public Object convertObjectValueToDataValue(Object objectValue,
Session session) {
if (isUUIDasByteArray) {
UUID uuid = (UUID)objectValue;
if (uuid == null) return null;
byte[] buffer = new byte[16];
ByteBuffer bb = ByteBuffer.wrap(buffer);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return buffer;
}
return objectValue;
}
#Override
public UUID convertDataValueToObjectValue(Object dataValue,
Session session) {
if (isUUIDasByteArray) {
byte[] bytes = (byte[])dataValue;
if (bytes == null) return null;
ByteBuffer bb = ByteBuffer.wrap(bytes);
long high = bb.getLong();
long low = bb.getLong();
return new UUID(high, low);
}
return (UUID) dataValue;
}
#Override
public boolean isMutable() {
return true;
}
#Override
public void initialize(DatabaseMapping mapping, Session session) {
final DatabaseField field;
if (mapping instanceof DirectCollectionMapping) {
// handle #ElementCollection...
field = ((DirectCollectionMapping) mapping).getDirectField();
} else {
field = mapping.getField();
}
if (session != null && session.getLogin()!= null && session.getLogin().getPlatform() != null) {
String platform = session.getLogin().getPlatform().getClass().getSimpleName();
if (platform.equals("PostgreSQLPlatform")) {
field.setSqlType(java.sql.Types.OTHER);
field.setTypeName("java.util.UUID");
field.setColumnDefinition("UUID");
isUUIDasByteArray = false;
} else if (platform.equals("H2Platform")) {
field.setColumnDefinition("UUID");
} else if (platform.equals("OraclePlatform")) {
field.setColumnDefinition("RAW(16)");
} else if (platform.equals("MySQLPlatform")) {
field.setColumnDefinition("BINARY(16)");
} else if (platform.equals("SQLServerPlatform")) {
field.setColumnDefinition("UNIQUEIDENTIFIER");
}
}
}
}
You don't need a converted. Use this column definition in the entity. You need to register the uuid extension first. This works with Postgres 10 and Wildfly 10.1
#Column(name = "UUID", nullable=false, insertable = false, columnDefinition="uuid DEFAULT uuid_generate_v4()")
private String uuid;