2 Replies Latest reply on Jul 10, 2007 8:55 AM by Bart Vanhaute

    java.util.Properties causes IllegalStateException on JBoss 4

    Alexander Slobodianik Newbie

      Hi all. My EJB2 contains java.util.Properties as CMP field and it was OK on JBoss 4.0.3SP1. But when deployed on 4.0.4GA, it causes following error during entity loading:


      java.lang.IllegalStateException: Failed to find a ctor in class java.util.Properties that takes an instance of interface java.util.Map as an argument.
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory.cloneValue(JDBCTypeFactory.java:308)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory.access$000(JDBCTypeFactory.java:56)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory$3.getFieldState(JDBCTypeFactory.java:105)
      at org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMP2xFieldBridge$FieldState.updateState(JDBCCMP2xFieldBridge.java:443)
      at org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMP2xFieldBridge$FieldState.setClean(JDBCCMP2xFieldBridge.java:431)
      at org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMP2xFieldBridge.setClean(JDBCCMP2xFieldBridge.java:262)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCLoadEntityCommand.execute(JDBCLoadEntityCommand.java:208)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCLoadEntityCommand.execute(JDBCLoadEntityCommand.java:88)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.loadEntity(JDBCStoreManager.java:646)
      at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.loadEntity(JDBCStoreManager.java:628)
      at org.jboss.ejb.plugins.CMPPersistenceManager.loadEntity(CMPPersistenceManager.java:406)
      ...

      I've searched the source code and found, that JDBCTypeFactory for all fields, which are Map implementation, tries to create a copy, using constructor which takes Map parameter:
      package org.jboss.ejb.plugins.cmp.jdbc;
      ...
      public final class JDBCTypeFactory
      ...
      /**
       * Field state factory for java.util.Map implementations. The state is
       * a deep copy of the value.
       */
       private static final CMPFieldStateFactory MAP = new CMPFieldStateFactory()
       {
       public Object getFieldState(Object fieldValue)
       {
       return cloneValue(fieldValue, Map.class);
       }
      
       public boolean isStateValid(Object state, Object fieldValue)
       {
       return (state == null ? fieldValue == null : state.equals(fieldValue));
       }
       };
      ...
      private static Object cloneValue(Object fieldValue, Class argType)
       {
       if(fieldValue == null)
       {
       return null;
       }
      
       Class valueType = fieldValue.getClass();
       Constructor ctor;
       try
       {
       ctor = valueType.getConstructor(new Class[]{argType});
       }
       catch(NoSuchMethodException e)
       {
       throw new IllegalStateException(
       "Failed to find a ctor in " + valueType +
       " that takes an instance of " + argType + " as an argument."
       );
       }
      

      and because of java.util.Properties hasn't such constructor, this leads to error.

      JBoss 4.0.3SP1 has different implementation of state factory for Map instances, that's why there is no error in that case:
      /**
       * Field state factory for java.util.Map implementations. The state is
       * a deep copy of the value.
       */
       private static final CMPFieldStateFactory MAP = new CMPFieldStateFactory()
       {
       public Object getFieldState(Object fieldValue)
       {
       return fieldValue == null ? null : new HashMap((Map)fieldValue);
       }
      
       public boolean isStateValid(Object state, Object fieldValue)
       {
       return (state == null ? fieldValue == null : state.equals(fieldValue));
       }
       };
      

      Of course, there are many workarounds, such as use of user state factory or replacing java.util.Properties by some other Map implementation. But is it a correct behavior to rely on presence of specific constructor? Maybe, it will be more secure to call no-arg constructor first and than putAll(Map m) method, which is part of Map interface?

      Thanks for advance.