Announcement Announcement Module
Collapse
No announcement yet.
Use Hibernate Entities in the web layer? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #31
    But I am still not convinced why DTOs are being used for same JVM client applications
    I attended Ben's ROO presentation in Stockholm yesterday and he said that one of the main reasons to use DTOs in the same JVM was to make the application more flexible in the face of new requirements i.e. if you use the non-DTO approach and the UI needs to present data in a *totally* different way later on then you're probably going to have to refactor some domain classes. This might have a potential impact on the data store since usually the domain object's lifecycle is tied to it. With the DTO approach the changes would be at least in theory limited to the DTO layer.

    Still...I agree, this smells a bit like YAGNI and is extra boilerplate although it's generated and synchronized automatically for you.

    Overall I thought ROO was a nice framework and the presentation was very good. Ben said that there's a 95% chance that they will open source it by the end of the year.
    Last edited by Manuel Palacio; Jul 3rd, 2007, 02:41 AM.

    Comment


    • #32
      I think it is also a matter of a design/architecture decision. If you decide to keep your rich domain objects inside the service layer you will have to do something to expose the data/functionality. The same goes for if you develop components which should expose there internals, that way you don't want to expose the domain objects.

      Comment


      • #33
        Originally posted by Manuel Palacio View Post
        one of the main reasons to use DTOs in the same JVM was to make the application more flexible in the face of new requirements i.e. if you use the non-DTO approach and the UI needs to present data in a *totally* different way later on then you're probably going to have to refactor some domain classes. This might have a potential impact on the data store since usually the domain object's lifecycle is tied to it. With the DTO approach the changes would be at least in theory limited to the DTO layer.
        That is one of the things that's always concerned me about it, that quick refactoring to give the method a more sensible name breaks the UI. Sure you can fix this with tooling, but even so. I just finished the POJOs in Action book and one thing that talked about was the adapter pattern. I've actually seen this used instead to wrap the entity and there providing a layer of indirection. Would that be a half-way house?
        Last edited by karldmoore; Aug 29th, 2007, 11:09 AM.

        Comment


        • #34
          Originally posted by karldmoore View Post
          That is one of the things that's always concerned me about it, that quick refactoring to give the method a more sensible name breaks the UI.
          The way I see it, is that, the contract between the domain layer and its clients (service layer, UI layer etc.) is always through the set of published interfaces. And once you have published your interface, it is very difficult to make the quick refactoring of method names. And I would not go for adapters (or DTOs) just to address such a change. As far as the implementation is concerned, they are never exposed to the higher up layers - hence I can make as much changes as I wish without any impact on my UI layer.

          Cheers.
          - Debasish

          Comment


          • #35
            If even with a published interface you expose the real domain object to the outer world, it could introspect it, and call some methods by reflection. However if you do that, and anything goes wrong well you deserved it .

            I think the biggest question to answer is that do you want to couple your domain layer be it directly be it by a set of (published) interfaces to the UI/WebServices?

            Also as we all know (well at least we should I guess) is that a software product is always in a state of flux, it is never (really) finished. Implementations change, properties appear/disappear. And with new requirements and improved insights in the application we might want to refactor our classes. However if my current design decision limits me in refactoring (i.e. published interfaces) then was it a good decision?

            I think in that regard that keeping your domain model inside your service layer and expose only some DTO's is better and more flexible. You could create some conversion (yet another? anti-corruption layer?) inside your service.

            Comment


            • #36
              Originally posted by mdeinum View Post
              Also as we all know (well at least we should I guess) is that a software product is always in a state of flux, it is never (really) finished. Implementations change, properties appear/disappear. And with new requirements and improved insights in the application we might want to refactor our classes. However if my current design decision limits me in refactoring (i.e. published interfaces) then was it a good decision?
              Quite! I hate working with software when you have no idea what this change might break. As I said before tooling can help but when I'm not sure if this property is used or not, it just ends up getting left there............ forever. We can never refactor , or when we do we change something that we never even though of. Granted it's published so that's the price we pay but I'm still undecided if I'm comfortable with that or not. For me there is somewhat of an appeal for DTOs, if I don't have to worry about the maintainance ala ROO.
              Last edited by karldmoore; Aug 29th, 2007, 11:08 AM.

              Comment


              • #37
                A very good technical reason not to use Hibernate entities in your Spring MVC view

                The topic of whether or not to use Hibernate entities in your Spring MVC view layer seems to be one that is based on preference. Granted, I have not read this entire thread, so there may very well be another good technical reason not to do it, but I have stumbled upon one that seems rather problematic. I decided that re-using my Hibernate entities as my Spring MVC command objects had more benefits then drawbacks... but as far as I am into building my application, I now wish I had decided otherwise.

                The story goes like this.... we have two tables....

                COMPANY( ID, some fields )
                ASSIGNMENT( ID, COMPANY_ID, some fields )

                Now, on the assignment adding page, there is a drop down with which you can select a company, and a company can only have one assignment. In order for Spring to bind the company id into the company entity assignment holds, the company entity in assignment must be initialized or else the Spring binder will give you some guff about it being null.

                In order to use HQL to query companies without assignments in a simple way, I added an assignment entity into the company entity. Due to the Spring binder problem, as a rule of thumb I initialize all associated entities. (Turns out in this particular instance I don't need to Initialize assignment in company as I never plan on binding to it with Spring, thus eliminating this problem.) Since the underlying company table doesn't have a foreign key for assignment, I used the mappedBy property of the OneToOne annotation.

                Everything in place, I build, and start Tomcat. During initialization an infinite loop results as it jumps back and forth between assignment and company.

                I may be violating some elementary rule about something you should never do with one of said technologies, but I thought it relevant to bring to the attention of those concerned about the issue regardless.

                -Jeff

                P.S. Try not to flame me too much, I'm only trying to help

                Comment


                • #38
                  Originally posted by alwaysLearning View Post
                  Now, on the assignment adding page, there is a drop down with which you can select a company, and a company can only have one assignment. In order for Spring to bind the company id into the company entity assignment holds, the company entity in assignment must be initialized or else the Spring binder will give you some guff about it being null.

                  In order to use HQL to query companies without assignments in a simple way, I added an assignment entity into the company entity. Due to the Spring binder problem, as a rule of thumb I initialize all associated entities. (Turns out in this particular instance I don't need to Initialize assignment in company as I never plan on binding to it with Spring, thus eliminating this problem.) Since the underlying company table doesn't have a foreign key for assignment, I used the mappedBy property of the OneToOne annotation.
                  No flaming, but what's the problem? Unfortunately I can't see from your post where you get into an infinite loop.

                  Joerg

                  Comment


                  • #39
                    Upon further investigation....

                    ..It appears the problem starts from a third entity, License, that holds a company reference. Well, the problem doesn't necessarily start there, but thats where this exception chain begins...

                    Code:
                    @Entity
                    @Table(name="LICENSE")
                    public class License {
                    	...
                    	@ManyToOne(cascade = CascadeType.REFRESH)
                    	@JoinColumn(name="COMPANYID_FK", referencedColumnName="COMPANYID_PK")
                    	private Company company = new Company();
                    	...
                    }
                    Code:
                    @Entity
                    @Table(name="COMPANY")
                    public class Company {
                    	...
                    	@OneToOne(mappedBy="company",fetch=FetchType.LAZY)
                    	private Assignment assignment = new Assignment();
                    	...
                    }
                    Code:
                    @Entity
                    @Table(name="ASSIGNMENT")
                    public class Assignment {
                    	...
                    	@OneToOne
                    	@JoinColumn(name="COMPANYID_FK", referencedColumnName="COMPANYID_PK")
                    	private Company company = new Company();
                    	...
                    }
                    And the stack trace that results from the exception generated when starting Tomcat...

                    Code:
                    2007-12-19 12:13:13,877 ERROR [org.springframework.web.servlet.DispatcherServlet] - Context initialization failed
                    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/dataAccessBeans.xml]: Invocation of init method failed; nested exception is org.hibernate.InstantiationException: could not instantiate test object entity.License
                    Caused by: 
                    org.hibernate.InstantiationException: could not instantiate test object entity.License
                    	at org.hibernate.engine.UnsavedValueFactory.instantiate(UnsavedValueFactory.java:25)
                    	at org.hibernate.engine.UnsavedValueFactory.getUnsavedIdentifierValue(UnsavedValueFactory.java:44)
                    	at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:44)
                    	at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:123)
                    	at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:434)
                    	at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:109)
                    	at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:55)
                    	at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226)
                    	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
                    	at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:915)
                    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:805)
                    	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:745)
                    	at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:134)
                    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1201)
                    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1171)
                    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:425)
                    	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
                    	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
                    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
                    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
                    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:284)
                    	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
                    	at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:331)
                    	at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:265)
                    	at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:235)
                    	at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
                    	at javax.servlet.GenericServlet.init(GenericServlet.java:212)
                    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                    	at java.lang.reflect.Method.invoke(Method.java:585)
                    	at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:244)
                    	at java.security.AccessController.doPrivileged(Native Method)
                    	at javax.security.auth.Subject.doAsPrivileged(Subject.java:517)
                    	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:276)
                    	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:162)
                    	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:115)
                    	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1155)
                    	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
                    	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4045)
                    	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4351)
                    	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
                    	at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
                    	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
                    	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
                    	at org.apache.catalina.core.StandardService.start(StandardService.java:516)
                    	at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
                    	at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
                    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                    	at java.lang.reflect.Method.invoke(Method.java:585)
                    	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
                    	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
                    Caused by: java.lang.reflect.InvocationTargetException
                    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
                    	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
                    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
                    	at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
                    	at org.hibernate.engine.UnsavedValueFactory.instantiate(UnsavedValueFactory.java:22)
                    	... 53 more
                    Caused by: java.lang.StackOverflowError
                    	at entity.Assignment.<init>(Assignment.java:36)
                    	at entity.Company.<init>(Company.java:34)
                    	at entity.Assignment.<init>(Assignment.java:40)
                    	at entity.Company.<init>(Company.java:34)
                    ...
                    	at entity.Assignment.<init>(Assignment.java:40)
                    	at entity.Company.<init>(Company.java:34)
                    I'll be happy to provide any other information anyone may be interested in.

                    Comment


                    • #40
                      From the stacktrace I get that it is an error even on the plain Java level: The constructor of Company seems to instantiate an Assignment instance. And the Assignment constructor does the same for the Company. This just can't work.

                      Joerg

                      Comment


                      • #41
                        The only reason they are initialized is for the Spring binder to work properly using them as command objects. This to me seems like a pretty good reason not to use Hibernate entities as command objects

                        Comment


                        • #42
                          Originally posted by alwaysLearning View Post
                          The only reason they are initialized is for the Spring binder to work properly using them as command objects. This to me seems like a pretty good reason not to use Hibernate entities as command objects
                          As I implied when saying it is already an error on the Java level: It has nothing to do with Hibernate. You would get the same error with DTOs. In your case it seems to be better to put that code into the controller instead of the domain objects, especially since it is a requirement of the web framework, not your domain.

                          Joerg

                          Comment


                          • #43
                            This might have been repeated before but wanted to run by to see that my assumptions are correct

                            Deciding whether to use DTO's or not to use them have been bothering me before I started my current work. And having known some of the issues with this approach, I've used my domain objects in the presentation layer.
                            But, have reached a stage where in I'm regretting my choice of doing it.
                            The problem mainly is when using domain entities (with one-to-one relation to other entities) in presentation layer (JSF). When the child entity is not available for the parent entity, it would be set to null by the ORM. This causes the problem because the binding on the presentation layer (JSF) calls some setters on the nested child entity and that throws "null" validation problems.

                            I think DTO's are required if the domain entities are editable from presentation layer. DTO's could be ignored for entities that might be used for only rendering info. Agreeing to what was said in the Hibernate in Action book.

                            Any feedback is much appreciated.

                            Comment


                            • #44
                              Originally posted by MMR View Post
                              ...When the child entity is not available for the parent entity, it would be set to null by the ORM. This causes the problem because the binding on the presentation layer (JSF) calls some setters on the nested child entity and that throws "null" validation problems.
                              ...
                              And how DTO would help? If child entity is null in the domain object why DTO may contain something else?

                              Regards,
                              Oleksandr

                              Comment


                              • #45
                                Just do it. I have finished this thought.
                                http://code.google.com/p/rich-hibernate-lazy/

                                Comment

                                Working...
                                X