foam-framework / foam2

FOAM: Feature-Oriented Active Modeller, Version 2
Apache License 2.0
73 stars 63 forks source link

Stack Overflow in Relationship #588

Open nick-prat opened 7 years ago

nick-prat commented 7 years ago

This code

DAO userDao = (DAO) boot.getX().get("userDAO");
    MapDAO accountDao = new MapDAO();
    accountDao.setOf(Account.getOwnClassInfo());
    accountDao.setX(boot.getX());

    for(int i = 0; i < USER_COUNT; i++) {
      User user = new User();
      user.setId(String.valueOf(i));
      Account[] accounts = new Account[ACCOUNT_COUNT];
      for(int j = 0; j < ACCOUNT_COUNT; j++) {
        accounts[j] = new Account();
        accounts[j].setOwner(user);
        accounts[j].setAccountInfo(new UserAccountInfo());
        accounts[j].setId(String.valueOf(i));
        accountDao.put(accounts[j]);
      }
      user.setAccount(accounts);
      userDao.put(user);
    }

Causes a stack overflow while using these models

foam.CLASS({
  name: 'User',
  package: 'net.nanopay.common.model',
  extends: 'foam.nanos.auth.User',
  properties: [
    {
      class: 'FObjectArray',
      of:    'net.nanopay.common.model.Phone',
      name:  'phones'
    },
    {
      class: 'Date',
      name:  'birthday'
    },
    {
      class: 'String',
      name:  'profilePicture'
    },
    {
      class: 'FObjectArray',
      of:    'net.nanopay.common.model.Address',
      name:  'address'
    },
    {
      class: 'FObjectArray',
      of:    'net.nanopay.common.model.Account',
      name:  'account'
    },
    {
      class: 'FObjectProperty',
      of: 'Transaction',
      name:  'transactions'
    }
  ]
});
foam.RELATIONSHIP({
  sourceModel: 'net.nanopay.common.model.User',
  targetModel: 'net.nanopay.common.model.Address',
  forwardName: 'address',
  inverseName: 'resident'
});
foam.RELATIONSHIP({
  sourceModel: 'net.nanopay.common.model.User',
  targetModel: 'net.nanopay.common.model.Account',
  forwardName: 'accounts',
  inverseName: 'owner'
});
foam.RELATIONSHIP({
  sourceModel: 'net.nanopay.common.model.User',
  targetModel: 'net.nanopay.common.model.Phone',
  forwardName: 'phones',
  inverseName: 'owner'
});
foam.CLASS({
  package: 'net.nanopay.common.model',
  name: 'Account',
  ids: [ 'accountId' ],
  properties: [
    {
      class: 'FObjectProperty',
      of:    'Limit',
      name:  'limit'
    },
    {
      class: 'FObjectProperty',
      of: 'AccountInfo',
      name: 'accountInfo'
    },
    {
      class: 'String',
      name: 'accountId'
    }
  ]
});

Beginning of the stack trace

java.lang.StackOverflowError
    at net.nanopay.common.model.Account.getClassInfo(Account.java:207)
    at foam.lib.json.Outputter.outputFObject(Outputter.java:119)
    at foam.lib.json.Outputter.output(Outputter.java:90)
    at foam.lib.json.Outputter.outputArray(Outputter.java:56)
    at foam.lib.json.Outputter.output(Outputter.java:94)
    at foam.core.AbstractPropertyInfo.toJSON(AbstractPropertyInfo.java:30)
    at foam.lib.json.Outputter.outputProperty(Outputter.java:81)
    at foam.lib.json.Outputter.outputFObject(Outputter.java:139)
    at foam.lib.json.Outputter.output(Outputter.java:90)
    at foam.core.AbstractPropertyInfo.toJSON(AbstractPropertyInfo.java:30)
TanayParikh commented 7 years ago

@nick-prat What values are you using for USER_COUNT and ACCOUNT_COUNT?

nick-prat commented 7 years ago

@TanayParikh I tested with multiple different numbers, the crash always occurred on the first pass anyway

TanayParikh commented 7 years ago

@nick-prat In that case I suspect there's a cyclic relationship in there (ie. User -> Account -> User), I'll look through the models. Have you tried stepping through?

TanayParikh commented 7 years ago

The issue is with the cyclic relationship caused by the foam.RELATIONSHIP. Temporary solution by @nick-prat is to use the userId.

foam.RELATIONSHIP({
  sourceModel: 'net.nanopay.common.model.User',
  targetModel: 'net.nanopay.common.model.Address',
  forwardName: 'address',
  inverseName: 'resident'
});

We'll need to update the Java JSON outputter to identify recursive relationships and stop output after a certain recursive depth.

kgrgreer commented 7 years ago

Relationships shouldn't be output in JSON.

On 8 August 2017 at 11:49, Tanay Parikh notifications@github.com wrote:

The issue is with the cyclic relationship caused by the foam.RELATIONSHIP. Temporary solution by @nick-prat https://github.com/nick-prat is to use the userId.

foam.RELATIONSHIP({ sourceModel: 'net.nanopay.common.model.User', targetModel: 'net.nanopay.common.model.Address', forwardName: 'address', inverseName: 'resident' });

We'll need to update the Java JSON outputter to identify recursive relationships and stop output after a certain recursive depth.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/foam-framework/foam2/issues/588#issuecomment-320998419, or mute the thread https://github.com/notifications/unsubscribe-auth/AHHXswp21lysyK7Fz9yK5MYHwF182sRDks5sWIObgaJpZM4Ot9P0 .