I have this class, but when I make a query it throws an exception:
org.hibernate.type.SerializationException: could not serialize
#Entity
public class Google implements Serializable{
#Id
String nombre;
String pass;
public Google() {
nombre = "defecto";
pass = "defecto";
}
public Google(String anom, String apass) {
nombre = anom;
pass = apass;
}
//Getters, setters..
}
This is the query, I am using JPA, hibernate and a MySQL DB, and the class implements Serializable I don't know which is the problem.
public void findNombresGoogle(Map<String, Amigo> anombresAmigos){
List<Google> resultados = new LinkedList<Google>();
Map<String, Amigo> nombresAmigos = anombresAmigos;
Query query = entityManager.createNativeQuery("FROM Google google WHERE "
+ "google.nombre IN (?1)", Google.class);
query.setParameter(1, nombresAmigos);
resultados = (List<Google>) query.getResultList();
}
In the following line :
query.setParameter(1, nombresAmigos);
nombresAmigos should be a List<String>, not a Map<String, Amigo>.
Related
I'm using EclipseLink to run some Native SQL. I need to return the data into a POJO. I followed the instructions at EclipseLink Docs, but I receive the error Missing descriptor for [Class]
The query columns have been named to match the member variables of the POJO. Do I need to do some additional mapping?
POJO:
public class AnnouncementRecipientsFlattenedDTO {
private BigDecimal announcementId;
private String recipientAddress;
private String type;
public AnnouncementRecipientsFlattenedDTO() {
super();
}
public AnnouncementRecipientsFlattenedDTO(BigDecimal announcementId, String recipientAddress, String type) {
super();
this.announcementId = announcementId;
this.recipientAddress = recipientAddress;
this.type = type;
}
... Getters/Setters
Entity Manager call:
public List<AnnouncementRecipientsFlattenedDTO> getNormalizedRecipientsForAnnouncement(int announcementId) {
Query query = em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT, AnnouncementRecipientsFlattenedDTO.class);
query.setParameter(1, announcementId);
return query.getResultList();
}
I found out you can put the results of a Native Query execution into a List of Arrays that hold Objects. Then one can iterate over the list and Array elements and build the desired Entity objects.
List<Object[]> rawResultList;
Query query =
em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT);
rawResultList = query.getResultList();
for (Object[] resultElement : rawResultList) {
AnnouncementDeliveryLog adl = new AnnouncementDeliveryLog(getAnnouncementById(announcementId), (String)resultElement[1], (String)resultElement[2], "TO_SEND");
persistAnnouncementDeliveryLog(adl);
}
You can only use native SQL queries with a class if the class is mapped. You need to define the AnnouncementRecipientsFlattenedDTO class as an #Entity.
Otherwise just create the native query with only the SQL and get an array of the data back and construct your DTO yourself using the data.
Old question but may be following solution will help someone else.
Suppose you want to return a list of columns, data type and data length for a given table in Oracle. I have written below a native sample query for this:
private static final String TABLE_COLUMNS = "select utc.COLUMN_NAME, utc.DATA_TYPE, utc.DATA_LENGTH "
+ "from user_tab_columns utc "
+ "where utc.table_name = ? "
+ "order by utc.column_name asc";
Now the requirement is to construct a list of POJO from the result of above query.
Define TableColumn entity class as below:
#Entity
public class TableColumn implements Serializable {
#Id
#Column(name = "COLUMN_NAME")
private String columnName;
#Column(name = "DATA_TYPE")
private String dataType;
#Column(name = "DATA_LENGTH")
private int dataLength;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public int getDataLength() {
return dataLength;
}
public void setDataLength(int dataLength) {
this.dataLength = dataLength;
}
public TableColumn(String columnName, String dataType, int dataLength) {
this.columnName = columnName;
this.dataType = dataType;
this.dataLength = dataLength;
}
public TableColumn(String columnName) {
this.columnName = columnName;
}
public TableColumn() {
}
#Override
public int hashCode() {
int hash = 0;
hash += (columnName != null ? columnName.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
if (!(object instanceof TableColumn)) {
return false;
}
TableColumn other = (TableColumn) object;
if ((this.columnName == null && other.columnName != null) || (this.columnName != null && !this.columnName.equals(other.columnName))) {
return false;
}
return true;
}
#Override
public String toString() {
return getColumnName();
}
}
Now we are ready to construct a list of POJO. Use the sample code below to construct get your result as List of POJOs.
public List<TableColumn> findTableColumns(String table) {
List<TableColumn> listTables = new ArrayList<>();
EntityManager em = emf.createEntityManager();
Query q = em.createNativeQuery(TABLE_COLUMNS, TableColumn.class).setParameter(1, table);
listTables = q.getResultList();
em.close();
return listTables;
}
Also, don't forget to add in your POJO class in persistence.xml! It can be easy to overlook if you are used to your IDE managing that file for you.
Had the same kind of problem where I wanted to return a List of POJOs, and really just POJOs (call it DTO if you want) and not #Entity annotated Objects.
class PojoExample {
String name;
#Enumerated(EnumType.STRING)
SomeEnum type;
public PojoExample(String name, SomeEnum type) {
this.name = name;
this.type = type;
}
}
With the following Query:
String query = "SELECT b.name, a.newtype as type FROM tablea a, tableb b where a.tableb_id = b_id";
Query query = getEntityManager().createNativeQuery(query, "PojoExample");
#SuppressWarnings("unchecked")
List<PojoExample> data = query.getResultList();
Creates the PojoExample from the database without the need for an Entity annotation on PojoExample. You can find the method call in the Oracle Docs here.
edit:
As it turns out you have to use #SqlResultSetMapping for this to work, otherwise your query.getResultList() returns a List of Object.
#SqlResultSetMapping(name = "PojoExample",
classes = #ConstructorResult(columns = {
#ColumnResult(name = "name", type = String.class),
#ColumnResult(name = "type", type = String.class)
},
targetClass = PojoExample.class)
)
Just put this anywhere under your #Entity annotation (so in this example either in tablea or tableb because PojoExample has no #Entity annotation)
public class UserTransfer{
private String u_email;
private String u_password;
public UserTransfer(String u_email,String u_password) {
this.u_email=u_email;
this.u_password=u_password;
}
public String getU_email() {
return u_email;
}
public void setU_email(String u_email) {
this.u_email = u_email;
}
public String getU_password() {
return u_password;
}
public void setU_password(String u_password) {
this.u_password = u_password;
}
}
#Repository
public interface UserTransRepositiory extends JpaRepository<UserTransfer, String> {
#Query(value ="SELECT " + "new paddelec.backend.model.UserTransfer(u.u_email,u.u_password)"
+" FROM tokens t JOIN users u ON t.u_email=u.u_email WHERE t.token= ?1")
UserTransfer findByToken(String Token);
}
This is my Code I try to generate a UserTranfer Object. The regular TokenTransfer and User Repository works just fine. But here I am getting the "java.lang.IllegalArgumentException: Not a managed type: *.UserTransfer" Exception.
UserTransfer must be a JPA entity -> annotate the class with #Entity
->
#Entity
public class UserTransfer{
private String u_email;
private String u_password;
Moreover don't forget that each entity must have an #Id . Example : if the u_email is the primary key , annotate it with #Id
I am trying exchange data stored on objects from a c++/qt project to java/spring using websockets and json. the communication via websockets are working fine, but in the java/spring the data arrives as null.
in the c++ class, i have something like that:
QString Usuario::toString() {
QString json = "{'email': "+email+"}";
QJsonDocument document = QJsonDocument::fromJson(json.toUtf8());
QByteArray prettyPrintedJson = document.toJson(QJsonDocument::Indented);
return prettyPrintedJson;
}
for classes like that:
usuario.h
class Usuario
{
private:
QString email;
public:
Usuario();
Usuario(QString email);
QString getEmail();
void setEmail(QString email);
QString toString();
};
registro.h
class Registro
{
private:
QString token;
Usuario usuario;
Produto produto;
Maquina maquina;
public:
Registro();
Registro(QString token, Usuario usuario, Produto produto, Maquina maquina);
Registro(Usuario usuario, Produto produto, Maquina maquina);
QString getToken();
void setToken(QString token);
Usuario getUsuario();
void setUsuario(Usuario usuario);
Produto getProduto();
void setProduto(Produto produto);
Maquina getMaquina();
void setMaquina(Maquina maquina);
QString toString();
};
in the java project, I have something like this:
#Component
public class CheckRegistro extends TextWebSocketHandler {
...
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException {
Registro value = new Gson().fromJson(message.getPayload(), Registro.class);
System.out.println("registro -> " + value);
String email_usuario = value.getUsuario().getEmail();
Usuario usuario = usuarioServ.findBy("email", email_usuario);
String nome_produto = value.getProduto().getNome();
Produto produto = produtoServ.findBy("nome", nome_produto);
Cliente cliente = clienteServ.findBy("usuario", usuario);
if(cliente.produtosComprados().contains(produto))
value = registroServ.findBy("produto", produto);
String result = new Gson().toJson(value);
session.sendMessage(new TextMessage(result));
}
...
}
and classes like that:
usuario.java
#Entity
public class Usuario extends Model implements UserDetails {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column
private String username;
#Column
private String password;
#Column
private String firstName;
#Column
private String lastName;
#Column
private String email;
...
}
registro.java
#Entity
public class Registro extends Model{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column
private String token;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Usuario usuario;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Produto produto;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Maquina maquina;
...
}
(for the record, some classes, like usuario have more fields in java than c++; others, like registro have the same fields either on the c++ side or in the java side).
someone can hint me what's wrong here? I know there is some libraries that can serialize the c++ object into json automatically, but I dunno if it's possible do that without add a third-party component to my project, just finding the right format for the string sent to the java socket.
update
I change the toString method in the c++ side to something like that:
QString Registro::toString() {
QJsonObject json{
{ "token", token },
{ "usuario", usuario.toString() },
{ "produto", produto.toString() },
{ "maquina", maquina.toString() }
};
QJsonDocument jsonDoc;
jsonDoc.setObject(json);
QByteArray prettyPrintedJson = jsonDoc.toJson(QJsonDocument::Indented);
return prettyPrintedJson;
}
and now, in the java side, the json string is printed like that:
"registro": "{\n \"maquina\": \"{\\n \\\"cpuArch\\\": \\\"x86_64\\\",\\n \\\"hostName\\\": \\\"DESKTOP-7GAPC4K\\\",\\n \\\"kernelType\\\": \\\"windows\\\",\\n \\\"kernelVersion\\\": \\\"10\\\",\\n \\\"productName\\\": \\\"Windows 10 Version 1909\\\",\\n \\\"ram\\\": \\\"RAM: 16030 MB\\\",\\n \\\"uniqueId\\\": \\\"c69d8cc7-8e66-4ea3-964a-792b2c2a6f80\\\"\\n}\\n\",\n \"produto\": \"{\\n \\\"nome\\\": \\\"prod1\\\"\\n}\\n\",\n \"token\": \"\",\n \"usuario\": \"{\\n \\\"email\\\": \\\"klebermo#gmail.com\\\"\\n}\\n\"\n}\n"
}
update 2
I change the method toString in the c++ side to something like that:
QString Registro::toString() {
return "{ \"token\": \""+token+"\", \"usuario\": "+usuario.toString()+", \"produto\": "+produto.toString()+", \"maquina\": "+maquina.toString()+" }";
}
and now in the java side I get a valid json, but here:
Registro value = new Gson().fromJson(message.getPayload(), Registro.class);
String email_usuario = value.getUsuario().getEmail();
Usuario usuario = usuarioServ.findBy("email", email_usuario);
String nome_produto = value.getProduto().getNome();
Produto produto = produtoServ.findBy("nome", nome_produto);
I am geting a NullPointerException for value.getUsuario().getEmail(). I really need send a class from the c++ side with all the fields from the java class? Is there any way to allow me send only the class with fields needed for this query? Or this is not the problem?
json in Usuario::toString is not valid JSON. QJsonDocument::fromJson returns null when parsing fails.
Assuming email is not quoted you need:
QString json = "{\"email\": \""+email+"\"}";
Alternatively, safer and simpler would be to use the JSON API:
QJsonObject json{
{ "email", email }
};
QJsonDocument document = QJsonDocument::fromJson(json);
QByteArray prettyPrintedJson = document.toJson(QJsonDocument::Indented);
basically I got following entity (extended by Lombok)
#Getter
#Setter
#Entity("FOO")
public class Foo{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private long id;
#ManyToOne
#JoinColumn(name = "FK_FEE", nullable = false)
private Fee fee;
#Column(name = "CCCS")
#Convert(converter = StringListConverter.class)
private List<String> cccs;
}
And the StringListConverter:
#Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
#Override
public String convertToDatabaseColumn(final List<String> list) {
String returnValue = null;
if (list != null) {
final List<String> trimmedList = new ArrayList<>();
for (final String strg : list) {
if (strg != null && !strg.isEmpty()) {
trimmedList.add(strg.trim());
}
}
returnValue = String.join(",", trimmedList);
}
return returnValue;
}
#Override
public List<String> convertToEntityAttribute(final String joined) {
List<String> returnValue = null;
if (joined != null) {
returnValue = new ArrayList<>();
final String[] splitted = joined.split(",");
for (final String strg : splitted) {
if (strg != null && !strg.isEmpty()) {
returnValue.add(strg.trim());
}
}
}
return returnValue;
}
}
And now I want to fetch a List of Foo where Fee.Id= 123 and Foo.cccs contains a specific string value.
#Repository
public interface FooRepository extends CrudRepository<Foo, Long> {
List<Foo> findByFeeIdAndCccsIn(Long feeId, String ccc);
}
But this does not work. Is the only way to solve this by writing an own query?
#Repository
public interface FooRepository extends CrudRepository<Foo, Long> {
#Query( "Select foo FROM Foo foo WHERE foo.fee.id = :feeId AND foo.cccs LIKE CONCAT(CONCAT('%', :cccs) ,'%')")
List<Foo> findByFeeIdAndCccsIn(#Param("feeId") Long feeId,#Param("cccs") String ccc);
}
Currently it seems the only solution is to use #Query and write a JPQL or native SQL query to get the data.
String SELECT_BY_FEE_AND_CCC = "Select foo FROM Foo foo "
+ " WHERE foo.fee.id = :feeId AND foo.cccs LIKE CONCAT(CONCAT('%', :ccc) ,'%')";
and attached with the #Query annotation like:
#Query(SELECT_BY_FEE_AND_CCC)
List<Foo> findByFeeIdAndCccsContains(#Param("feeId") Long feeId, #Param("ccc") String ccc);
NOTE/EDIT:
Sometimes you have to join the foreign table to have access on it's properties.
String SELECT_BY_FEE_AND_CCC = "Select foo FROM Foo foo "
+ " JOIN foo.fee fee "
+ " WHERE fee.id = :feeId AND foo.cccs LIKE CONCAT(CONCAT('%', :ccc) ,'%')";
And now I want to fetch a List of Foo where Fee.Id= 123 and Foo.cccs
contains a specific string value.
You have specific requirements. According to Spring Data JPA doc what you are trying to do is not supported.
So you should use #Query for your requirements.
When I try to read written data from hibernate database I get this error:
Exception in thread "AWT-EventQueue-0" javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of familyTree.data.Data1.bio
This is class for saving my data with constructor, I pasted important part from it:
#Entity
#Table(name="DATA.PERSON")
public class Data1 {
#Id
#Column(name = "ID")
#GeneratedValue
private int id;
...
#Column(name = "BIO")
public final String bio;
...
public Data1(String names, Integer dayBirth, Integer monthBirth, Integer yearBirth, String bio, String fileID) {
this.names = names;
this.dayBirth = dayBirth;
this.monthBirth = monthBirth;
this.yearBirth = yearBirth;
this.bio = bio;
this.fileID = fileID;
}
...
public String getBiog() {
return bio;
}
So, when I try to do this:
data = new Data1(names, dayBirth, monthBirth, yearBirth, bio, fileID);
fireActionPerformed();
DatabaseUtils.spremiRezultatTesta(data);
List<?> podaci = DatabaseUtils.dohvatiRezultateTestova();
String ffff = podaci.get(0).toString();
System.out.print(ffff);
I get mentioned exception. Any help?
Database entity for that is created like this: BIO VARCHAR(80) NOT NULLand I can normally read it with SELECT FROM query in database.
Here is my DatabaseUtils class, used for saving and loading from database, if needed:
public class DatabaseUtils {
public static void spremiRezultatTesta(Data1 data) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("HibernatePersistenceUnit");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(data);
em.getTransaction().commit();
}
#SuppressWarnings("unchecked")
public static List<Data1> dohvatiRezultateTestova() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("HibernatePersistenceUnit");
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("FROM Data1");
return query.getResultList();
}
}