7 Replies Latest reply on Apr 11, 2008 4:14 AM by alesj

    Anonymous beans

    alesj

      Brian is looking for this issue to get resolved asap (he's having a bunch of beans that don't need any name, mostly inner beans):
      - http://jira.jboss.com/jira/browse/JBMICROCONT-281
      - http://jira.jboss.com/jira/browse/JBMICROCONT-28
      - http://www.jboss.com/index.html?module=bb&op=viewtopic&t=89581&postdays=0&postorder=asc&start=0
      - http://www.jboss.com/index.html?module=bb&op=viewtopic&t=105759

      Is there any preferred to do metadata cloning?
      I'm thinking of something like this:

       public Object clone()
       {
       AbstractBeanMetaData clone = new AbstractBeanMetaData();
       doClone(clone);
       return clone;
       }
      
       protected void doClone(AbstractBeanMetaData clone)
       {
       super.doClone(clone);
       clone.setBean(bean);
       clone.setName(name);
       clone.setAliases(aliases);
       ...
       }
      


      Do we already have some similar code, to clone collections:
       @SuppressWarnings("unchecked")
       public static <U extends JBossInterface, T extends Collection<U>> T clone(T collection)
       {
       if (collection == null)
       return null;
      
       try
       {
       Class<? extends Collection> collectionClass = collection.getClass();
       T clone = (T)collectionClass.newInstance();
       for (U item : collection)
       clone.add((U)item.clone());
       return clone;
       }
       catch (Throwable t)
       {
       throw new RuntimeException(t);
       }
       }
      


        • 1. Re: Anonymous beans

           

          "alesj" wrote:

           public Object clone()
           {
           AbstractBeanMetaData clone = new AbstractBeanMetaData();
           doClone(clone);
           return clone;
           }
          



          No you should use covariant return types
          public AbstractBeanMetaData clone()
          {
          ...
          }
          




           protected void doClone(AbstractBeanMetaData clone)
           {
           super.doClone(clone);
           clone.setBean(bean);
           clone.setName(name);
           clone.setAliases(aliases);
           ...
           }
          



          Why are you "cloning" fields that are direct referenes? What does it achieve?


          Do we already have some similar code, to clone collections:
           @SuppressWarnings("unchecked")
           public static <U extends JBossInterface, T extends Collection<U>> T clone(T collection)
           {
           if (collection == null)
           return null;
          
           try
           {
           Class<? extends Collection> collectionClass = collection.getClass();
           T clone = (T)collectionClass.newInstance();
           for (U item : collection)
           clone.add((U)item.clone());
           return clone;
           }
           catch (Throwable t)
           {
           throw new RuntimeException(t);
           }
           }
          


          This looks overally complicated and an obvious misuse of generics again.
          Why have generics then do all the casting and suppress warnings?

          The way to clone collections is something like:

          Set<String> aliases = this.getAliases();
          if (aliases != null)
           clone.setAliases(new HashSet<String>(aliases));
          


          • 2. Re: Anonymous beans
            alesj

             

            "adrian@jboss.org" wrote:

            Why are you "cloning" fields that are direct referenes? What does it achieve?

            You mean immutables?
            Does Object::clone do that already for me?

            "adrian@jboss.org" wrote:

            This looks overally complicated and an obvious misuse of generics again.
            Why have generics then do all the casting and suppress warnings?

            The way to clone collections is something like:

            Set<String> aliases = this.getAliases();
            if (aliases != null)
             clone.setAliases(new HashSet<String>(aliases));
            

            All would be fine if Object::getClass returned the right Class generic. :-)

            I don't wanna do that extra 2 lines (null check and the new collection instantiation) for every cloning of the collection.
            And I guess I would also have to iterate over all the collection items that are not immutable and clone them before adding them to new collection instance.
            Another code that I don't want to duplicate.

            • 3. Re: Anonymous beans
              alesj

               

              "alesj" wrote:

              And I guess I would also have to iterate over all the collection items that are not immutable and clone them before adding them to new collection instance.

              I need MetaDataVisitorNode to extend JBossInterface in order to clone AbstractCollectionMetaData and AbstractMapMetaData:
              public class AbstractCollectionMetaData extends AbstractTypeMetaData
               implements Collection<MetaDataVisitorNode>, Serializable
              {
               private static final long serialVersionUID = 2L;
              
               /** The collection */
               protected List<MetaDataVisitorNode> collection = new ArrayList<MetaDataVisitorNode>();
              
              ...
              
              public class AbstractMapMetaData extends AbstractTypeMetaData
               implements Map<MetaDataVisitorNode, MetaDataVisitorNode>, Serializable
              {
               private static final long serialVersionUID = 2L;
              
               /** The map */
               private Map<MetaDataVisitorNode, MetaDataVisitorNode> map = new HashMap<MetaDataVisitorNode, MetaDataVisitorNode>();
              

              So that I can iterate over the items and call item::clone().

              • 4. Re: Anonymous beans

                No. Just make MetaDataVisitorNode implement Cloneable.

                • 5. Re: Anonymous beans
                  alesj

                   

                  "adrian@jboss.org" wrote:
                  No. Just make MetaDataVisitorNode implement Cloneable.

                  How does that help me with cloning the items?
                  Since the item::clone() method comes from Object, where it is protected.
                  e.g.
                   public AbstractCollectionMetaData clone()
                   {
                   AbstractCollectionMetaData clone = (AbstractCollectionMetaData)super.clone();
                   clone.collection = getDefaultInstance();
                   for (MetaDataVisitorNode item : collection)
                   clone.collection.add((MetaDataVisitorNode)item.clone());
                   return clone;
                   }
                  


                  • 6. Re: Anonymous beans
                    brian.stansberry

                    There's a problem with the way the anonymous bean impl (NestedBeanHandler I think) is generating names. Looks like it's getting confused about where it is in the nested bean hierarchy and ends up trying to apply the same name to multiple beans.

                    The -beans.xml I'm trying to deploy can be found at https://svn.jboss.org/repos/jbossas/trunk/cluster/src/etc/jboss-cache-manager-beans.xml . When I try to deploy it in AS trunk I get this:

                    2008-04-10 22:45:20,150 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] (main) Error installing to Real: name=vfsfile:/home/bes/dev/jboss/trunk/build/output/jboss-5.0.0.CR1/server/all/deploy/cluster/jboss-cache-manager-beans.xml state=PreReal mode=Manual requiredState=Real
                    org.jboss.deployers.spi.DeploymentException: Error deploying: CacheConfigurationRegistry$runtimeConfig
                     at org.jboss.deployers.spi.DeploymentException.rethrowAsDeploymentException(DeploymentException.java:49)
                     at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.deploy(BeanMetaDataDeployer.java:92)
                     at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.deploy(BeanMetaDataDeployer.java:46)
                     at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalDeploy(AbstractSimpleRealDeployer.java:62)
                     at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.deploy(AbstractRealDeployer.java:50)
                     at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:174)
                     at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:970)
                     at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:991)
                     at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:911)
                     at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:348)
                     at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1394)
                     at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:786)
                     at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:914)
                     at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:836)
                     at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:674)
                     at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:456)
                     at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:594)
                     at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:541)
                     at org.jboss.system.server.profileservice.ProfileServiceBootstrap.loadProfile(ProfileServiceBootstrap.java:259)
                     at org.jboss.system.server.profileservice.ProfileServiceBootstrap.start(ProfileServiceBootstrap.java:137)
                     at org.jboss.bootstrap.AbstractServerImpl.start(AbstractServerImpl.java:409)
                     at org.jboss.Main.boot(Main.java:209)
                     at org.jboss.Main$1.run(Main.java:544)
                     at java.lang.Thread.run(Thread.java:595)
                    Caused by: java.lang.IllegalStateException: CacheConfigurationRegistry$runtimeConfig is already installed.
                     at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:577)
                     at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:443)
                     at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.deploy(BeanMetaDataDeployer.java:88)
                     ... 22 more
                    


                    Note that the runtimeConfig property is not an immediate child of the CacheConfigurationRegistry bean. It's a property of "StandardSessionCacheConfig" and "FieldSessionCacheConfig".

                    To add to the challenge, "StandardSessionCacheConfig" and "FieldSessionCacheConfig" really can be anonymous. I just gave them names for human readability. So any solution should work even if they were anonymous.

                    BTW, what I'm trying to do in the part of this file that uses anonymous beans is parse XML to create a set of JBoss Cache configurations. JBC has its own XML format and parser that I can use to accomplish this. It didn't have system property substitution, but I added that earlier this week. So I can use that. I'd prefer to use MC to do this. But don't let me totally rearrange your schedule; I have a workaround.



                    • 7. Re: Anonymous beans
                      alesj

                      Ah, I see.
                      Looks like I've tried to be too user friendly.
                      I'll fix this in NestedBeanHandler, adding counter to inner beans that come from property as well.

                      But if someone wants that user friendly generated names, one can override the AbstractBeanMetaData::createNestedBeanHandler, providing custom NestedBeanHandler::generateName.