Results 1 to 4 of 4

Thread: BeanModelReader cannot handle BeanModel subtyping

  1. #1
    Sencha User
    Join Date
    Apr 2011
    Posts
    6

    Post BeanModelReader cannot handle BeanModel subtyping

    Don't know if it's my miss understanding, or really a bug. I'll first describe the issue, then give the solution of it.

    A. Issue
    I have a class named ChangeReq, implements Serializable, and with a BeanModelMarker:
    Code:
    @BEAN(ChangeReq.class)
    public interface ChangeReqBeanModel extends BeanModelMarker
    {
    }
    It has 2 subclasses: BillingChangeReq, and BudgetChangeReq, both with BeanModelMarker.
    When I create RemoteService, I made a interface like that:
    Code:
    @RemoteServiceRelativePath("service")
    public interface PersistenceService extends RemoteService
    {
        // ...
        List<ChangeReq> getChangeRequests();
        // ...
    }
    And in ChangeReqWindow, I create a grid to show data:
    Code:
            RpcProxy<List<ChangeReq>> proxy = new RpcProxy<List<ChangeReq>>() {
                @Override
                public void load(Object loadConfig, AsyncCallback<List<ChangeReq>> callback)
                {
                    PersistenceServiceAsync service = (PersistenceServiceAsync) Registry.get(Explorer.SERVICE);
                    service.getChangeRequests(callback);
                }
            };
            BeanModelReader reader = new BeanModelReader();
    
            // loader and store
            ListLoader<ListLoadResult<ModelData>> loader = new BaseListLoader<ListLoadResult<ModelData>>(proxy, reader);
            ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
    
            loader.load();
    
            List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
            // ...
    
            grid = new Grid<BeanModel>(store, new ColumnModel(configs));
            // ...
    That's all. When I implement the RemoveService as followed:
    Code:
    @SuppressWarnings("serial")
    public class PersistenceServiceImpl extends RemoteServiceServlet implements PersistenceService
    {
        @Override
        public List<ChangeReq> getChangeRequests()
        {
            List<ChangeReq> list = new ArrayList<ChangeReq>();
            list.add(new BillingChangeReq(new Date(), "BillingChangeRequest", "AAA", "AAA", "AAA",
                    ChangeReqState.APPROVED, 1000));
            list.add(new BudgetChangeReq(new Date(), "BudgetChangeRequest", "BBB", "BBB", "BBB", ChangeReqState.REJECTED, 1000));
    
            return list;
        }
    }
    Then the grid will no error reporting nor showing any rows.
    B. Reason (maybe)
    I set some breakpoints in code. And saw that the BeanModelReader got 2 ChangeReq instances, so, it's OK for RemoteService.
    And I tested, just when I set the first row to the ChangeReq, but not the BillingChangeReq, or BudgetChangeReq, the grid will show all records.

    I checked the BeanModelReader's code, and found that the problem may exists in this function:
    Code:
      @SuppressWarnings({"unchecked", "rawtypes"})
      public ListLoadResult<ModelData> read(Object loadConfig, Object data) {
        if (data instanceof List) {
          List<Object> beans = (List) data;
          if (beans.size() > 0) {
            if (factoryForEachBean) {
              List models = new ArrayList(beans.size());
              for (Object o : beans) {
                BeanModelFactory factory = BeanModelLookup.get().getFactory(o.getClass());
                assert factory != null : "No BeanModelFactory found for " + o.getClass();
                models.add(factory.createModel(o));
              }
              return newLoadResult(loadConfig, models);
            } else {
              BeanModelFactory factory = BeanModelLookup.get().getFactory(beans.get(0).getClass());
              // beans.get(0) may not be the instance of "ChangeReq"
              // So the Factory may be a subtyped class's Factory
              // And the reader will not match the proxy or proxy's AsyncCallback???
              assert factory != null : "No BeanModelFactory found for " + beans.get(0).getClass();
              return newLoadResult(loadConfig, (List) factory.createModel(beans));
            }
          }
          return newLoadResult(loadConfig, (List) beans);
    
        } else if (data instanceof ListLoadResult) {
          ListLoadResult result = (ListLoadResult) data;
          List beans = result.getData();
          if (beans.size() > 0) {
            List converted;
            if (factoryForEachBean) {
              converted = new ArrayList(beans.size());
              for (Object o : beans) {
                BeanModelFactory factory = BeanModelLookup.get().getFactory(o.getClass());
                assert factory != null : "No BeanModelFactory found for " + o.getClass();
                converted.add(factory.createModel(o));
              }
            } else {
              BeanModelFactory factory = BeanModelLookup.get().getFactory(beans.get(0).getClass());
              assert factory != null : "No BeanModelFactory found for " + beans.get(0).getClass();
              converted = factory.createModel(beans);
            }
            beans.clear();
            beans.addAll(converted);
          }
          return (ListLoadResult) data;
        }
        assert false : "Error converting data";
    
        return null;
      }
    C. Solution
    To create and use a Customed BeanModelReader as followed:
    Code:
        private Class<?> modelClass;
    
        public BeanModelReader(Class<?> modelClass)
        {
            this.modelClass = modelClass;
        }
    
        @SuppressWarnings({
                "unchecked", "rawtypes"
        })
        public ListLoadResult<ModelData> read(Object loadConfig, Object data)
        {
            if (data instanceof List) {
                List<Object> beans = (List) data;
                if (beans.size() > 0) {
                    BeanModelFactory factory = BeanModelLookup.get().getFactory(modelClass);
                    assert factory != null : "No BeanModelFactory found for " + modelClass;
                    return newLoadResult(loadConfig, (List) factory.createModel(beans));
                }
                return newLoadResult(loadConfig, (List) beans);
    
            } else if (data instanceof ListLoadResult) {
                ListLoadResult result = (ListLoadResult) data;
                List beans = result.getData();
                if (beans.size() > 0) {
                    List converted;
                    BeanModelFactory factory = BeanModelLookup.get().getFactory(modelClass);
                    assert factory != null : "No BeanModelFactory found for " + modelClass;
                    converted = factory.createModel(beans);
                    beans.clear();
                    beans.addAll(converted);
                }
                return (ListLoadResult) data;
            }
            assert false : "Error converting data";
    
            return null;
        }
    
        // Usage:
            BeanModelReader reader = new BeanModelReader(ChangeReq.class);
    
            // loader and store
            ListLoader<ListLoadResult<ModelData>> loader = new BaseListLoader<ListLoadResult<ModelData>>(proxy, reader);
            ListStore<BeanModel> store = new ListStore<BeanModel>(loader);
    
            loader.load();

  2. #2
    Sencha Premium Member
    Join Date
    Sep 2007
    Posts
    13,976

    Default

    You will need to add the marker also for your two subclasses.

  3. #3
    Sencha User
    Join Date
    Apr 2011
    Posts
    6

    Default

    Yes, I really added two BeanModelMarker to each of sub-class. But I think maybe the BeanModelMarker will not auto-generate the getter for the inherited fields? Anyway, when I pointed the super class to BeanModelReader, the problem resolved.

  4. #4
    Sencha Premium Member
    Join Date
    Sep 2007
    Posts
    13,976

    Default

    Pointing the superclass as you did will not fully work. The only solution is to add additional marker interfaces. With BeanModelMarker you only mark this particular class, no subclasses.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •