java hibernate orm factory-pattern

java - ¿Por qué Hibernate no requiere un constructor de argumentos?



orm factory-pattern (9)

Consulte esta sección de la especificación de lenguaje Java que explica la diferencia entre clases internas estáticas y no estáticas: http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.3

Una clase interna estática no es conceptualmente diferente de una clase general regular declarada en un archivo .java.

Como Hibernate necesita instanciar ProjectPK independientemente de la instancia del Proyecto, ProjectPK necesita ser una clase interna estática o declararse en su propio archivo .java.

referencia org.hibernate.InstantiationException: ningún constructor predeterminado

El constructor sin argumentos es un requisito (herramientas como Hibernate usan la reflexión en este constructor para crear instancias de objetos).

Recibí esta respuesta ondulada a mano, pero ¿podría alguien explicar más? Gracias


El hibernate es un marco ORM que admite la estrategia de acceso de campo o de propiedad. Sin embargo, no admite el mapeo basado en el constructor, tal vez lo que le gustaría? - debido a algunos problemas como

¿Qué sucede si tu clase contiene muchos constructores?

public class Person { private String name; private Integer age; public Person(String name, Integer age) { ... } public Person(String name) { ... } public Person(Integer age) { ... } }

Como puede ver, se trata de un problema de incoherencia porque Hibernate no puede suponer a qué constructor se debe llamar. Por ejemplo, supongamos que necesita recuperar un objeto Persona almacenado

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

¿Qué constructor debería Hibernar para recuperar un objeto Persona? Puedes ver ?

Y finalmente, al usar la reflexión, Hibernate puede instanciar una clase a través de su constructor no-arg. Entonces cuando llamas

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

Hibernate instanciará su objeto Person de la siguiente manera

Person.class.newInstance();

Que según la documentación API

La clase se instancia como si fuera una nueva expresión con una lista de argumentos vacía

Moraleja de la historia

Person.class.newInstance();

es parecido a

new Person();

Nada más


En realidad, puedes instanciar clases que no tienen constructor 0-args; puedes obtener una lista de los constructores de una clase, elegir uno e invocarlo con parámetros falsos.

Si bien esto es posible, y supongo que funcionaría y no sería problemático, tendrás que aceptar que es bastante extraño.

Construir objetos como lo hace Hibernate (creo que invoca el constructor 0-arg y luego modifica los campos de la instancia directamente a través de Reflection. Quizás sepa cómo llamar a los setters) va un poco en contra de cómo se construye un objeto en Java: invoque el constructor con los parámetros apropiados para que el nuevo objeto sea el que desea. Creo que crear instancias de un objeto y luego mutarlo es algo "anti-Java" (o diría, Java puramente anti-teórico), y definitivamente, si haces esto a través de la manipulación directa de campo, va a la encapsulación y todas esas cosas encapsuladas .

Creo que la forma correcta de hacerlo sería definir en el mapeo de Hibernate cómo un objeto debería ser instanciado a partir de la información en la fila de la base de datos usando el constructor apropiado ... pero esto sería más complejo, lo que significa que ambos serían incluso iguales. más complejo, el mapeo sería más complejo ... y todo para ser más "puro"; y no creo que esto tenga una ventaja sobre el enfoque actual (aparte de sentirse bien acerca de hacer las cosas "de la manera correcta").

Habiendo dicho eso, y viendo que el enfoque de Hibernate no es muy "limpio", la obligación de tener un constructor 0-arg no es estrictamente necesaria, pero puedo entender algo el requisito, aunque creo que lo hicieron de una manera puramente "correcta" "motivos, cuando se desviaron de la" forma correcta "(aunque por razones razonables) mucho antes de eso.


Erm, lo siento todo el mundo, pero Hibernate no requiere que sus clases tengan un constructor sin parámetros. La especificación JPA 2.0 lo requiere, y esto es muy cojo en nombre de JPA. Otros marcos como JAXB también lo requieren, que también es muy cojo en nombre de esos marcos.

(En realidad, JAXB supuestamente permite fábricas de entidades, pero insiste en crear instancias de estas fábricas por sí mismo, lo que requiere que tengan un constructor sin parámetros , que en mi libro es tan bueno como no permitir fábricas; !

Pero Hibernate no requiere tal cosa.

Hibernate admite un mecanismo de interceptación (consulte "Interceptor" en la documentación ), que le permite crear instancias de sus objetos con los parámetros de construcción que necesiten.

Básicamente, lo que haces es que cuando configuras Hibernate, le pasas un objeto que implementa la interfaz org.hibernate.Interceptor , e hibernate org.hibernate.Interceptor el método instantiate() de esa interfaz siempre que necesite una nueva instancia de un objeto tuyo. , entonces su implementación de ese método puede new sus objetos de la manera que desee.

Lo hice en un proyecto y funciona como un encanto. En este proyecto, hago cosas a través de JPA siempre que sea posible, y solo uso las funciones de Hibernate como el interceptor cuando no tengo otra opción.

Hibernate parece algo inseguro al respecto, ya que durante el inicio emite un mensaje de información para cada una de mis clases de entidad, diciéndome INFO: HHH000182: No default (no-argument) constructor for class y class must be instantiated by Interceptor , pero luego más tarde los instauro por interceptor, y está contento con eso.

Para responder a la pregunta "por qué" de las herramientas que no sean Hibernate , la respuesta es "sin ninguna buena razón", y esto está demostrado por la existencia del interceptor hibernate. Existen muchas herramientas que podrían haber estado soportando algún mecanismo similar para la creación de instancias de objetos cliente, pero no lo hacen, por lo que crean los objetos por sí mismos, por lo que deben requerir constructores sin parámetros. Estoy tentado de creer que esto está sucediendo porque los creadores de estas herramientas piensan en sí mismos como programadores de sistemas ninja que crean marcos llenos de magia para ser utilizados por programadores de aplicaciones ignorantes, que (por lo que piensan) nunca en sus sueños más salvajes tendrán una necesidad de construcciones tan avanzadas como ... Patrón de fábrica . (De acuerdo, estoy tentado de pensarlo. En realidad, no lo creo. Estoy bromeando).


Es mucho más fácil crear objetos con un constructor sin parámetros a través de la reflexión, y luego rellenar sus propiedades con datos a través de la reflexión, que intentar hacer coincidir los datos con parámetros arbitrarios de un constructor parametrizado, cambiando los nombres / conflictos de nombres, la lógica indefinida dentro del constructor. conjuntos de parámetros que no coinciden con las propiedades de un objeto, etcétera.

Muchos ORM y serializadores requieren constructores sin parámetros, porque los constructores paramétricos a través de la reflexión son muy frágiles, y los constructores sin parámetros proporcionan estabilidad a la aplicación y control sobre el comportamiento del objeto para el desarrollador.


Hibernate crea una instancia de tus objetos. Entonces necesita poder crear una instancia de ellos. Si no hay un constructor no-arg, Hibernate no sabrá cómo crear una instancia, es decir, qué argumento aprobar.

La documentación de hibernación dice:

4.1.1. Implementar un constructor sin argumentos

Todas las clases persistentes deben tener un constructor predeterminado (que puede ser no público) para que Hibernate pueda instanciarlas usando Constructor.newInstance() . Se recomienda tener un constructor predeterminado con al menos visibilidad de paquete para la generación de proxy en tiempo de ejecución en Hibernate.


Hibernate necesita crear instancias como resultado de sus consultas (a través de la reflexión), Hibernate se basa en el constructor no-arg de entidades para eso, por lo que debe proporcionar un constructor sin argumentos. Lo que no está claro?


Hibernate usa proxies para cargas perezosas. Si no define un constructor o lo vuelve privado, algunas cosas pueden funcionar, las que no dependen del mecanismo proxy. Por ejemplo, cargar el objeto (sin constructor) directamente usando query API.

Pero, si usa session.load method (), se enfrentará a InstantiationException del generador de proxy lib debido a la falta de disponibilidad del constructor.

Este tipo informó una situación similar:

http://kristian-domagala.blogspot.com/2008/10/proxy-instantiation-problem-from.html


Hibernate y el código en general que crea objetos a través de la reflexión usan Class<T>.newInstance() para crear una nueva instancia de tus clases. Este método requiere un constructor público no-arg para poder crear una instancia del objeto. Para la mayoría de los casos de uso, proporcionar un constructor sin argumentos no es un problema.

Hay hacks basados ​​en la serialización que pueden funcionar sin tener un constructor no-arg, ya que la serialización usa la magia jvm para crear objetos sin invocar al constructor. Pero esto no está disponible en todas las máquinas virtuales. Por ejemplo, XStream puede crear instancias de objetos que no tienen un constructor no-arg público, pero solo ejecutándose en un modo llamado "mejorado" que está disponible solo en ciertas máquinas virtuales. (Ver el enlace para más detalles.) Los diseñadores de Hibernate seguramente eligieron mantener la compatibilidad con todas las máquinas virtuales y así evitan tales trucos, y usan el método de reflexión oficialmente admitido Class<T>.newInstance() requiere un constructor sin Class<T>.newInstance() .