3 Replies Latest reply on May 7, 2009 1:49 PM by brian.stansberry

    MetaMapper not being used for property setter

    brian.stansberry

      In my work on adding management to the service binding manager-related beans, I've written a MetaMapper subclass and applied it to a property via @MetaMapping on the getter. My MetaMapper gets invoked when the property is read, but when a ManagementView.updateComponent call results in a call to the setter, the MetaMapper isn't used, resulting in an exception.

      Walking through this in a debugger, I think the problem is in BeanMetaDataICF:

       public void setValue(BeanInfo beanInfo, ManagedProperty property,
       BeanMetaData attachment, MetaValue value)
       {
       ClassLoader prevLoader = SecurityActions.getContextClassLoader();
       String beanName = attachment.getName();
       // First look to the mapped name
       String name = property.getMappedName();
       if (name == null)
       name = property.getName();
       try
       {
       ClassLoader loader = getClassLoader(attachment);
       // Set the mbean class loader as the TCL
       SecurityActions.setContextClassLoader(loader);
      
       PropertyInfo propertyInfo = property.getField(Fields.PROPERTY_INFO, PropertyInfo.class);
       if(propertyInfo == null)
       propertyInfo = beanInfo.getProperty(name);
       if(propertyInfo == null)
       throw new IllegalArgumentException("No matching property found: " + name + "/" + beanName);
      
       if(propertyInfo.isWritable() == false)
       {
       if(log.isTraceEnabled())
       log.trace("Skipping get of non-writable property: "+propertyInfo);
       return;
       }
       Object plainValue = metaValueFactory.unwrap(value, propertyInfo.getType());
       Object bean = locateBean(beanName);
      
       // Only update if the bean is not null
       if(bean != null)
       propertyInfo.set(bean, plainValue);
      
       BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(attachment);
       builder.addPropertyMetaData(name, plainValue);
      
       }
       catch(Throwable e)
       {
       throw new IllegalStateException("Failed to set property value: "+name + "/" + beanName, e);
       }
       finally
       {
       SecurityActions.setContextClassLoader(prevLoader);
       }
       }
      


      The method has access to the ManagedProperty, and my MetaMapper is attached to the ManagedProperty as a transient attachment. AFAICT the way the MetaMapper is found when the getter is called is via that transient attachment. But the above code does not look for the MetaMapper there; it just delegates to DefaultMetaValueFactory, which uses MetaMapper.getMetaMapper(). MetaMapper.getMetaMapper() will only find a MetaMapper if it is

      1) Attached to the TypeInfo
      2) Specified via an annotation on the class

      Here the type is java.util.Set<org.jboss.services.binding.ServiceBindingMetadata>, so of course #2 doesn't apply and adding an attachment so #1 would work seems problematic. I suspect that's why the approach of adding the MetaMapper as a transient attachment to the ManagedProperty is there.

      Should BeanMetaDataICF have logic added to look for the MetaMapper in the ManagedProperty? Or should the MetaMapper have somehow been attached to the TypeInfo so #1 would work? I doubt the latter.

      I think I can find a workaround for this for my SBM work, but it will force me to annotate a class with @MetaMapping when I don't want to. I'm trying to avoid adding hard-coded dependencies on jboss-managed and jboss-metatype to the SBM classes.