martes, 12 de marzo de 2013

Hibernate InvalidMappingException

Trabajando con Hibernate, en una relación 1-n bidireccional, obtuve un error en un mapeo

SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Initial SessionFactory creation failed.org.hibernate.InvalidMappingException: Could not parse mapping document from resource comentario1nbi.hbm.xml
Exception in thread "main" java.lang.NullPointerException
    at com.blog.dao.PostDAO.crearPost(PostDAO.java:48)
    at com.hib.TestHibBlog.main(TestHibBlog.java:26)



Esto surgía, porque en comentario1nb1.hbm.xml había puesto  como name el nombre de la tabla, y debe ser el del VO
 
  <many-to-one name="postVO" column="idPost"  />



<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
 <class name="com.blog.vo.Comentario1nBiVO" table="comentarios1nBi">
  <id name="id" type="int" column="id" >
   <generator class="identity"/>
  </id>
 
  <property name="cuerpo">
   <column name="cuerpo" />
  </property>
  <property name="fecha">
   <column name="fecha"/>
  </property>
 
  <!-- muchos comentarios pertenecen a un post
  indico el nombre del atributo dentro
  de Comentario1nBiVO al cual haré referencia
  con mi clave.
  La columna es la columna de posts, que es clave. -->
  <many-to-one name="postVO" column="idPost"  />
 </class>
</hibernate-mapping>



<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
 <class name="com.blog.vo.Post1nBiVO" table="posts1nBi">
  <id name="id" type="int" column="idPost" >
   <generator class="identity"/>
  </id>

  <property name="idAutor" type="int" column="idAutor"/>

  <property name="fecha">
   <column name="fecha" />
  </property> 
  <property name="titulo">
   <column name="titulo" />
  </property>
  <property name="contenido">
   <column name="contenido"/>
  </property>
 
  <list name="comentarios" cascade="all-delete-orphan">  
     <key column="idPost" /><!-- cuál columna de la tabla post será la clave externa -->
    <index column="ORDEN" />  <!-- para guardar en el mismo orden, una columna nueva -->
    <!-- ahora sí indico que hay una relación de 1 a n -->
    <one-to-many class="com.blog.vo.Comentario1nBiVO" />
  </list>

 </class>
</hibernate-mapping>




package com.blog.vo;

import java.util.Date;

public class Comentario1nBiVO {
        private int id;
        private String fecha;
        private Post1nBiVO postVO;
       
       
        public Comentario1nBiVO() {
            super();
            // TODO Auto-generated constructor stub
        }
        public Comentario1nBiVO(String fecha, String cuerpo) {
            super();
            this.fecha = fecha;
            this.cuerpo = cuerpo;
        }
        private String cuerpo;
        /**
         * @return the id
         */
        public int getId() {
            return id;
        }
        /**
         * @param id the id to set
         */
        private void setId(int id) {
            this.id = id;
        }
       
        /**
         * @return the fecha
         */
        public String getFecha() {
            return fecha;
        }
        /**
         * @param fecha the fecha to set
         */
        public void setFecha(String fecha) {
            this.fecha = fecha;
        }
        /**
         * @return the cuerpo
         */
        public String getCuerpo() {
            return cuerpo;
        }
        /**
         * @param cuerpo the cuerpo to set
         */
        public void setCuerpo(String cuerpo) {
            this.cuerpo = cuerpo;
        }
        /**
         * @return the postVO
         */
        public Post1nBiVO getPostVO() {
            return postVO;
        }
        /**
         * @param postVO the postVO to set
         */
        public void setPostVO(Post1nBiVO postVO) {
            this.postVO = postVO;
        }

       
}




package com.blog.vo;

import java.util.ArrayList;
import java.util.List;

public class Post1nBiVO {

        private int id;
        private int idAutor;
        private String fecha;
        private String titulo;
        private String contenido;
        private List comentarios=new ArrayList();
       
        /**
         * DEBE EXISTIR UN CONSTRUCTOR POR DEFECTO PARA QUE
         * HIBERNATE FUNCIONE
         */
        public Post1nBiVO(){
            super();
        }
       
    public Post1nBiVO(int idAutor, String fecha, String titulo, String contenido) {
        super();
        this.idAutor = idAutor;
        this.fecha = fecha;
        this.titulo = titulo;
        this.contenido = contenido;
    }       
   
    public void addComentario(Comentario1nBiVO comentario){
        comentarios.add(comentario);
    }
       
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

       
        public String getFecha() {
            return fecha;
        }
        public void setFecha(String string) {
            this.fecha = string;
        }
        public String getTitulo() {
            return titulo;
        }
        public void setTitulo(String titulo) {
            this.titulo = titulo;
        }
        public String getContenido() {
            return contenido;
        }
        public void setContenido(String contenido) {
            this.contenido = contenido;
        }

        /**
         * @return the idAutor
         */
        public int getIdAutor() {
            return idAutor;
        }

        /**
         * @param idAutor the idAutor to set
         */
        public void setIdAutor(int idAutor) {
            this.idAutor = idAutor;
        }

        /**
         * @return the comentarios
         */
        public List getComentarios() {
            return comentarios;
        }

        /**
         * @param comentarios the comentarios to set
         */
        public void setComentarios(List comentarios) {
            this.comentarios = comentarios;
        }
       
       
}











jueves, 28 de febrero de 2013

Excepción en Hibernate

Esta excepción a mí me ocurrió cuando estaba intentando actualizar un registro de cuyo id no tenemos existencia en la base de datos, porque acababa de ser borrado.


org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
    at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)




lunes, 25 de febrero de 2013

Hacer un redirect con struts

Problema: He creado un post, y el forward me llevó al listado de post, sin embargo, como la url es /crearActionPost.do  , si le doy a refrescar me volverá a crear el mismo post.  Quiero que me cambie la url, para que aunque refresquen, sea imposible volver a crear el mismo post, que para crear un post, deban iniciar el proceso.

Solución:

   Esto sería lo que tendría habitualmente:  //return mapping.findForward("mostrarTodo");
 Esta, una primera aproximación: 
    // ActionForward ac = mapping.findForward("mostrarTodo");
    // ac.setRedirect(true);
    //return ac;
   En realidad ActionForward, hereda de ForwardConfig, entonces, puedo decirle, que quiero que 
vaya al listado pero indicándole que haga un redirect:       
    ForwardConfig f = new ActionRedirect(mapping.findForward("mostrarTodo"));
    f.setRedirect(true);
    return (ActionForward) f;

html:href .vs. a href

Problema:  Queremos llamar desde una jsp a un action de struts.
Posibilidades:  Usar una etiqueta "a" de html o usar una etiqueta "Conclusión:  Mejor usar la de Struts, puesto que relativiza y puedes llamar a un action sin .do y sin tener en cuenta dónde desde dónde haces la llamada.  Peor si quieres imprimir varios parámetros o usar el <bean:write>


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

    pageEncoding="ISO-8859-1"%>

    <%@page import="vo.PostVO" %>

    <%@page import="java.util.LinkedList" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>

<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title></title>

</head>

<body>

<logic:iterate name="listaPost"  scope="session" id="post" >

    <bean:write property="titulo" name="post"/>

    <bean:write property="descripcion" name="post"/>

    <bean:write property="fecha" name="post"/>

    <a href="postAction.do?method=detallesPost&id=<bean:write property="id" name="post"/>">Más detalles...</a></br></br>

</logic:iterate> 
 
 
<!--


OPCIÓN 1:

con a href, debo buscar la ruta relativa y colocar el .do 

--> 
 <a href="../crearPost.do">Crear nuevo Post</a>
 
 
<!--

OPCIÓN 2:con html:link, no es necesario colocar .do ni las relativas

-->  


 <html:link action="crearPost">Crear nuevo Post versión pro</html:link> 
 
<!--


OPCIÓN 3:con html:link, pasándole un parámetro ID, donde adquiere el valor que tendrá la propiedad id dentro del form llamado post

http://localhost:8080/nombre_proyecto/crearPost.do?method=crear&titulo=4&ID=2

--> 

 
 <html:link action='crearPost?method=crear&titulo=4' paramName="post" 
paramProperty="id" paramId="ID" >Crear nuevo Post versión pro</html:link>



</body>

</html>






lunes, 21 de enero de 2013

Hibernate desde 0 usando Struts 1.3.10

Hoy me topé con la necesidad de integrar Hibernate junto con Struts, y aquí os dejo unos pasos y unos buenos tutoriales

1.-Me bajé el zip con el contenido de hibernate.  https://sourceforge.net/projects/hibernate/?source=dlp  y en el eclipse, en la carpeta lib, metí los jars siguientes:
  • Los que estaban dentro de required ( hibernate-distribution-3.6.10.Final-dist\hibernate-distribution-3.6.10.Final\lib\required) : antlr-2.7.6, commons-collections-3.1, dom4j-1.6.1, javassist-3.12.0.GA, jta-1.1,  slf4j-api-1.6.1
  • Los de hibernate propiamente dicho (\hibernate-distribution-3.6.10.Final-dist\hibernate-distribution-3.6.10.Final) : hibernate3  e hibernate3testing 
  • El de JPA (hibernate-distribution-3.6.10.Final-dist\hibernate-distribution-3.6.10.Final\lib\jpa):  hibernate-jpa-2.0-api-1.0.1.Final
    • Este jar hay que meterlo para evitar la excepción Exception in thread “main” java.lang.NoClassDefFoundError: javax/persistence/EntityListeners    (solución hallada en http://technicalrecyclebin.wordpress.com/category/j2ee/hibernate/ )
2.-Metí en mi proyecto el jar de un conector de mysql, en mi caso:  mysql-connector-java-5.1.22-bin.jar

3.-Yo seguí un muy buen tutorial de creación de la aplicación, donde tras indicarte los ficheros que tienes que crear te brinda la oportunidad de dejar la prueba ejecutada
http://blog.sencide.com/2011/03/hibernate-tutorial-for-beginners.html

4.-Para ese mismo tutorial, os dejo los scripts de creación de mysql, puesto que , tuve algún error, por ejemplo, se me olvidó crear las claves primaras como autoincremental, y si no lo hacía, me salía el siguiente error:   org.hibernate.HibernateException: The database returned no natively generated identity value  o también otro que indicaba que no tenía un valor por defecto en el id.  OJO, yo le llamé a la base de datos, hibernatestruts  (con lo cual difiere del ejemplo del tutorial)

delimiter $$

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(100) DEFAULT NULL,
  `last_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8$$

delimiter $$

CREATE TABLE `tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  `description` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8$$

SELECT * FROM hibernatestruts.users;

delimiter $$

CREATE TABLE `tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  `description` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8$$

SELECT * FROM hibernatestruts.users;

5.-Una vez que ejecuté como una aplicación Java el test.  Procedí a introducirlo con Struts.  Para ello, tenía una aplicación creada con el struts-blank de la versión 1.3.10, creé un Action para poder ejecutar mi código y seguí el siguiente tutorial:

http://bernabetorres.wordpress.com/2011/07/27/integracion-de-hibernate-en-struts-1-3-10/

y este

http://www.mkyong.com/struts/struts-hibernate-integration-example/


6.-Finalmente, me leí una documentación adicional

Introducción resumida:  http://hareenlaks.blogspot.com.es/2011/03/introduction-to-hibernate.html
Introducción: http://docs.jboss.org/hibernate/core/3.5/reference/en/html/tutorial.html
Lenguaje HQL:  http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html
Variado: http://viralpatel.net/blogs/introduction-to-hibernate-framework-architecture/

7.-No olvidar, una buena herramienta para el eclipse (en mi caso eclipse Juno)
http://marketplace.eclipse.org/node/420896#.UP0aLoaTrIU