Thread: [OJB-developers] Ojbgen code generator
Brought to you by:
thma
From: Hoang, H. <Hai...@co...> - 2002-05-30 04:54:31
|
I've some code that read the repository.xml and generate java code for the following pattern from previous project (ATG) and now I want to port over to OJB and donate it to the ojb community. For example, if I have a class descriptor and these are classes will be generated: User (interface) UserImpl (class) UserManager (interface) UserManagerImpl (class) 1. I would like to know, which class parses the repository.xml for information purposes only (without validation), so I can use the information in the repository to generate code. 2. Can we possibly add a <interface.name>com.xyz.Permission</interface.name> tag to the class descriptor along with <class.name>com.xyz.PermissionImpl</class.name>? 3. Can I reuse the metadata package to store the parsed information from the repository.xml without required runtime classes? for example, if I have a <class.name>com.xyz.PermissionImpl</class.name> in one of my class descriptor and the file is not yet genereated, will this causes me problem? Thank you, Hai |
From: Matthew b. <mat...@ya...> - 2002-05-30 06:19:35
|
I think the appendTableWithJoins routine has a bug with parenthesis. the routine is recursive to build out all the joins (with parens) upon entry, the stmtFromPos ( the position of the FROM keyword in the SQL being generated) is set because joinSyntaxType is SQL92_JOIN_SYNTAX and the table is the root. So let's say it's set to 150. since I have a complex path, with lots of joins, I end up calling appendTableWithJoins from within appendTableWithJoins. Now, stmtFromPos is 0 because table is not root. Near the bottom of the function, you see a buf.insert(stmtFromPos, "("); if iterator has next. In my case it has next, so the ( is inserted at stmtFromPos which is 0, so I end up with SQL that looks like this: (((SELECT .... obviously those parens should go after the FROM clause. the solution is to make the stmtFromPos a parameter and pass it along. I wanted to get opinions on this fix, as the SQL being generated for our really complex case is still wrong (parens aren't working right) and I wanted to make sure this wasn't a symptom of another problem. protected void appendTableWithJoins(TableAlias table, StringBuffer where, StringBuffer buf) { int stmtFromPos = 0; if (joinSyntaxType == SQL92_JOIN_SYNTAX && table == root) { stmtFromPos = buf.length(); // BRJ : point after FROM } if (!(joinSyntaxType == SQL92_NOPAREN_JOIN_SYNTAX && table != root)) { buf.append(table.table); buf.append(" "); buf.append(table.alias); } if (!table.hasJoins()) { return; } for (Iterator it = table.iterateJoins(); it.hasNext();) { Join join = (Join) it.next(); if (joinSyntaxType == SQL92_JOIN_SYNTAX) { if (join.isOuter) { buf.append(" LEFT OUTER JOIN "); } else { buf.append(" INNER JOIN "); } if (join.right.hasJoins()) { buf.append("("); appendTableWithJoins(join.right, where, buf); buf.append(")"); } else { appendTableWithJoins(join.right, where, buf); } buf.append(" ON "); join.appendJoinEqualities(buf); if (it.hasNext()) { buf.insert(stmtFromPos, "("); buf.append(")"); } } else if (joinSyntaxType == SQL92_NOPAREN_JOIN_SYNTAX) { if (join.isOuter) { buf.append(" LEFT OUTER JOIN "); } else { buf.append(" INNER JOIN "); } buf.append(join.right.table); buf.append(" "); buf.append(join.right.alias); buf.append(" ON "); join.appendJoinEqualities(buf); appendTableWithJoins(join.right, where, buf); } else { buf.append(","); appendTableWithJoins(join.right, where, buf); if (where.length() > 0) { where.append(" AND "); } join.appendJoinEqualities(where); } } } The SQL being generated for my complex case is: SELECT A0.matrix_calc_efdt_uuid,A0.begin_effective_date,A0.end_effective_date,A0.activation_date, A0.deactivation_date,A0.matrix_calc_version_uuid FROM (((MATRIX_CALC_EFDT A0 INNER JOIN (MATRIX_CALC_VERSION A1 INNER JOIN (statement_VAR A2 INNER JOIN PARTICIPANT A3 ON A2.participant_uuid=A3.participant_uuid) INNER JOIN HIERARCHY_OBJECT A5 ON A2.organization_uuid=A5.hierarchy_object_uuid) INNER JOIN JOB A4 ON A2.job_uuid=A4.job_uuid) INNER JOIN (statement A6 INNER JOIN UNIT A7 ON A6.unit_uuid=A7.unit_uuid) ON A2.statement_uuid=A6.statement_uuid) ON A1.statement_var_uuid=A2.statement_var_uuid) ON A0.matrix_calc_version_uuid=A1.matrix_calc_version_uuid WHERE (((( ( ( A0.activation_date <= ? AND A0.deactivation_date > ? OR A0.deactivation_date IS NULL ) AND A0.begin_effective_date <= ?) AND A0.end_effective_date > ? OR A0.end_effective_date IS NULL ) AND A3.participant_uuid IS NULL ) AND A4.job_uuid IS NULL ) AND A5.hierarchy_object_uuid IS NULL ) AND A7.unit_uuid = ? which if you drop it into Query Analyzer or try to execute it against MS SQL Server, you get an error with not a lot of information, but it looks like it's right after the FROM. thoughts? --------------------------------- Do You Yahoo!? Yahoo! - Official partner of 2002 FIFA World Cup |
From: Matthew b. <mat...@ya...> - 2002-05-30 06:46:26
|
I'm looking through the code trying to thoroughly grok how extents are supported, and I have to admit I'm a little bit puzzled :) I was wondering if someone out there could comment on my understanding of how things work: Consider having two objects mapped to the same table, but they one doesn't inherit from the other. To be concrete, we have OperatingUnit and EnterpriseUnit. If I execute an OQL query "select unit from com.somecompany.OperatingUnit" I would expect to get back all the operatingunits and none of the enterpriseunits. To support that, I've included an ojbConcreteClass mapping for each of the unit types. OJB does it's thing and finally ends up calling the .next() on the RsIterator, during which OJB will call getObjectFromResultSet which will eventually call readObjectFrom readObjectFrom then checks the ojbConcreteClass attribute, but can't really use this as a discriminator since it doesn't know what you asked for (for instance, the first row in the UNIT table is an enterprise unit, and I asked for operatingunits) so it tries to build the EnterpriseUnit using the query results of the OperatingUnit. If EnterpriseUnit doesn't have the same fields mapped in the same order as OperatingUnit, building the new instance of the object will throw an exception. the exception makes its way back to the .next() routine where it is caught as an Exception and rethrown as a NoSuchElementException which is NOT caught in getCollectionByQuery getCollectionByQuery is extent aware, and is ready to deal with having object materialized that don't match what was asked for if ((itemClass.equals(candidate.getClass())) || (Proxy.isProxyClass(candidate.getClass())) || (candidate instanceof VirtualProxy)) is the important peice of code however, this code is unlikely to actually be called because Object candidate = i.next(); is probably going to throw a NoSuchElementException exception. There are a couple other places where we load the object, check the type and try to materialize one of those objects. Using the new row[] array instead of the resultset means we have to be aware of the ordering of results (we can't get them by name) which causes a problem with 2 objects mapped to the same table with different order of mappings. I can live with that, but the materialization of an extent object with extra attributes failing because row[] doesn't contain all those values is not good. If you grokked all that, here's a potential solution: when creating the select SQL, if more than one object is mapped to the table, either load the union of all the fields that *could* be used dependent on object type, then store them by name in a hashmap (or come up with a lighter solution to get the columns by name). Then you would be guaranteed that the actual object could be created if need be. This solution would allow for people to query on base class and still get back base and sub classes all mapped to same table. Other solution would be to somehow append the objConcreteClass discriminator to the where clause, but that would not allow for loading subclasses as base objects, so I don't think it's a good solution. Comments? --------------------------------- Do You Yahoo!? Yahoo! - Official partner of 2002 FIFA World Cup |
From: Thomas M. <tho...@ho...> - 2002-05-31 13:30:06
|
Hi again, Matthew baird wrote: > I'm looking through the code trying to thoroughly grok how extents are > supported, and I have to admit I'm a little bit puzzled :) I was > wondering if someone out there could comment on my understanding of how > things work: > > Consider having two objects mapped to the same table, but they one > doesn't inherit from the other. To be concrete, we have OperatingUnit > and EnterpriseUnit. > > If I execute an OQL query "select unit from > com.somecompany.OperatingUnit" I would expect to get back all the > operatingunits and none of the enterpriseunits. To support that, I've > included an ojbConcreteClass mapping for each of the unit types. > > OJB does it's thing and finally ends up calling the .next() on the > RsIterator, during which OJB will call getObjectFromResultSet which will > eventually call readObjectFrom > > readObjectFrom then checks the ojbConcreteClass attribute, but can't > really use this as a discriminator since it doesn't know what you asked > for (for instance, the first row in the UNIT table is an enterprise > unit, and I asked for operatingunits) so it tries to build the > EnterpriseUnit using the query results of the OperatingUnit. > > If EnterpriseUnit doesn't have the same fields mapped in the same order > as OperatingUnit, building the new instance of the object will throw an > exception. the exception makes its way back to the .next() routine where > it is caught as an Exception and rethrown as a NoSuchElementException > which is NOT caught in getCollectionByQuery > > getCollectionByQuery is extent aware, and is ready to deal with having > object materialized that don't match what was asked for > > if ((itemClass.equals(candidate.getClass())) > || (Proxy.isProxyClass(candidate.getClass())) > || (candidate instanceof VirtualProxy)) > > is the important peice of code however, this code is unlikely to > actually be called because Object candidate = i.next(); is probably > going to throw a NoSuchElementException exception. > > There are a couple other places where we load the object, check the type > and try to materialize one of those objects. Using the new row[] array > instead of the resultset means we have to be aware of the ordering of > results (we can't get them by name) which causes a problem with 2 > objects mapped to the same table with different order of mappings. I can > live with that, but the materialization of an extent object with extra > attributes failing because row[] doesn't contain all those values is not > good. > I agree. We'll have to improve the "mapping on one table"-stuff. (We'll also need support for the third possible mapping of inheritance hierarchies, where attributes may come from different tables.) > If you grokked all that, here's a potential solution: > > when creating the select SQL, if more than one object is mapped to the > table, either load the union of all the fields that *could* be used > dependent on object type, then store them by name in a hashmap (or come > up with a lighter solution to get the columns by name). Then you would > be guaranteed that the actual object could be created if need be. This > solution would allow for people to query on base class and still get > back base and sub classes all mapped to same table. > I think this is the way to go. > Other solution would be to somehow append the objConcreteClass > discriminator to the where clause, but that would not allow for loading > subclasses as base objects, so I don't think it's a good solution. > I agree. cheers, Thomas > Comments? > > > > > > > > > > > ------------------------------------------------------------------------ > *Do You Yahoo!?* > Yahoo! <http://rd.yahoo.com/welcome/*http://fifaworldcup.yahoo.com> - > Official partner of 2002 FIFA World Cup |
From: Jakob B. <jbr...@ho...> - 2002-05-30 07:21:09
|
hi matthew, the sql looks quite ok.=20 i first introduced stmtFromPos as an instance variable and i think oleg = made it a local variable.=20 jakob ----- Original Message -----=20 From: Matthew baird=20 To: obj...@li...=20 Sent: Thursday, May 30, 2002 8:19 AM Subject: [OJB-developers] bug in sql generation I think the appendTableWithJoins routine has a bug with parenthesis. = the routine is recursive to build out all the joins (with parens) upon = entry, the stmtFromPos ( the position of the FROM keyword in the SQL = being generated) is set because joinSyntaxType is SQL92_JOIN_SYNTAX and = the table is the root. So let's say it's set to 150. since I have a complex path, with lots of joins, I end up calling = appendTableWithJoins from within appendTableWithJoins. Now, stmtFromPos = is 0 because table is not root. Near the bottom of the function, you see = a buf.insert(stmtFromPos, "("); if iterator has next. In my case it has = next, so the ( is inserted at stmtFromPos which is 0, so I end up with = SQL that looks like this: (((SELECT .... obviously those parens should go after the FROM clause.=20 the solution is to make the stmtFromPos a parameter and pass it along. = I wanted to get opinions on this fix, as the SQL being generated for our = really complex case is still wrong (parens aren't working right) and I = wanted to make sure this wasn't a symptom of another problem. protected void appendTableWithJoins(TableAlias table, StringBuffer = where, StringBuffer buf) { int stmtFromPos =3D 0; if (joinSyntaxType =3D=3D SQL92_JOIN_SYNTAX && table =3D=3D = root) { stmtFromPos =3D buf.length(); // BRJ : point after FROM }=20 if (!(joinSyntaxType =3D=3D SQL92_NOPAREN_JOIN_SYNTAX && table = !=3D root)) { buf.append(table.table); buf.append(" "); buf.append(table.alias); }=20 if (!table.hasJoins()) { return; }=20 for (Iterator it =3D table.iterateJoins(); it.hasNext();) { Join join =3D (Join) it.next(); if (joinSyntaxType =3D=3D SQL92_JOIN_SYNTAX) { if (join.isOuter) { buf.append(" LEFT OUTER JOIN "); } else { buf.append(" INNER JOIN "); } if (join.right.hasJoins()) { buf.append("("); appendTableWithJoins(join.right, where, buf); buf.append(")"); } else { appendTableWithJoins(join.right, where, buf); } buf.append(" ON "); join.appendJoinEqualities(buf);=20 if (it.hasNext()) { buf.insert(stmtFromPos, "("); buf.append(")"); } } else if (joinSyntaxType =3D=3D SQL92_NOPAREN_JOIN_SYNTAX) { if (join.isOuter) { buf.append(" LEFT OUTER JOIN "); } else { buf.append(" INNER JOIN "); } buf.append(join.right.table); buf.append(" "); buf.append(join.right.alias); buf.append(" ON "); join.appendJoinEqualities(buf); appendTableWithJoins(join.right, where, buf); } else { buf.append(","); appendTableWithJoins(join.right, where, buf); if (where.length() > 0) { where.append(" AND "); } join.appendJoinEqualities(where); } } }=20 The SQL being generated for my complex case is:=20 SELECT = A0.matrix_calc_efdt_uuid,A0.begin_effective_date,A0.end_effective_date,A0= .activation_date, A0.deactivation_date,A0.matrix_calc_version_uuid FROM=20 (((MATRIX_CALC_EFDT A0 INNER JOIN (MATRIX_CALC_VERSION A1 INNER JOIN = (statement_VAR A2 INNER JOIN PARTICIPANT A3=20 ON A2.participant_uuid=3DA3.participant_uuid) INNER JOIN = HIERARCHY_OBJECT A5 ON A2.organization_uuid=3DA5.hierarchy_object_uuid)=20 INNER JOIN JOB A4 ON A2.job_uuid=3DA4.job_uuid) INNER JOIN (statement = A6 INNER JOIN UNIT A7 ON A6.unit_uuid=3DA7.unit_uuid)=20 ON A2.statement_uuid=3DA6.statement_uuid) ON = A1.statement_var_uuid=3DA2.statement_var_uuid)=20 ON A0.matrix_calc_version_uuid=3DA1.matrix_calc_version_uuid =20 WHERE (((( ( ( A0.activation_date <=3D ?=20 AND A0.deactivation_date > ? OR A0.deactivation_date IS NULL )=20 AND A0.begin_effective_date <=3D ?)=20 AND A0.end_effective_date > ? OR A0.end_effective_date IS NULL )=20 AND A3.participant_uuid IS NULL ) AND A4.job_uuid IS NULL )=20 AND A5.hierarchy_object_uuid IS NULL ) AND A7.unit_uuid =3D ?=20 which if you drop it into Query Analyzer or try to execute it against = MS SQL Server, you get an error with not a lot of information, but it = looks like it's right after the FROM.=20 thoughts? -------------------------------------------------------------------------= ----- Do You Yahoo!? Yahoo! - Official partner of 2002 FIFA World Cup |
From: Thomas M. <tho...@ho...> - 2002-05-31 11:49:12
|
Hi Hoang, Hoang, Hai wrote: > I've some code that read the repository.xml Reading a repository.xml is done by ojb.broker.metadata.RepositoryPersistor. I see no reason to duplicate this functionality. If your code uses the RepositoryPersistor, OK! If not please refactor it to use the RepositoryPersistor. > and generate java code That's interesting. You are generating code from a ojb.broker.metadata.DescriptorRepository or directly from the parsed repository.xml file? If you are generating from DescriptorRepository you solution could be the step towards the OJB code genartor stuff! Are you using a special library for code generation, or do you generate Java code manually? I'd prefer using an existing opensource library! > for the > following pattern from previous project (ATG) and now I want to port over to > OJB and donate it to the ojb community. > thanks! > For example, if I have a class descriptor and these are classes will be > generated: > > User (interface) > UserImpl (class) > UserManager (interface) > UserManagerImpl (class) > IMO there should be some kind of template mechanism to allow user-defined generation schemes. Generating those for classes may be perfect for your environment. But others would like different schemes. In my company we use: User (interface) UserBaseImpl implements User (abtract class, only getters and setters are implemented) UserImpl extends UserBaseImpl (all other methods are implemented here) UserHome (factory class) We should not force OJB use to use a specific generation scheme. > 1. I would like to know, which class parses the repository.xml for > information purposes only (without validation), so I can use the information > in the repository to generate code. Have a look at ojb.broker.metadata.RepositoryPersistor. This guy builds up the DescriptorRepository from a repository.xml (and in the near future from a repository.jdo) file. BUT:it uses validation! (I don't understand why you do not to use XML validation???) > > 2. Can we possibly add a > <interface.name>com.xyz.Permission</interface.name> tag to the class > descriptor along with <class.name>com.xyz.PermissionImpl</class.name>? > There is already a mechanism to define interface based extends in the repository. For example there is an extent declaration for "InterfaceArticle" in our junit testsuite repository_junit.xml declaring all implementations of this IF. This could also be used to get your required information The DescriptorRepository is meant for object/relational mapping information. Metainformation related to codegeneration patterns should be kept in a separate place. The best way (as mentioned above) would be to provide a template mechanism to allow maximum flexibility. > 3. Can I reuse the metadata package to store the parsed information from > the repository.xml without required runtime classes? for example, if I have > a <class.name>com.xyz.PermissionImpl</class.name> in one of my class > descriptor and the file is not yet genereated, will this causes me problem? > Oops, you got me! This is an aspect I did not think about before! In fact the current DescriptorRepository relies on existing persistent classes. There are several places where the XmlRepositoryHandler tries a Class.forName(...), which will cause a lot of exceptions in the case you are describing. The same holds true for attribute fields (or getter/setter methods if you are using bean access). But it should not be too difficult to change this. A ClassDescriptor should be marked with a special tag saying "this class could not be found and should be generated". cheers, Thomas > Thank you, > > Hai > > > _______________________________________________________________ > > Don't miss the 2002 Sprint PCS Application Developer's Conference > August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm > > _______________________________________________ > Objectbridge-developers mailing list > Obj...@li... > https://lists.sourceforge.net/lists/listinfo/objectbridge-developers > > > > |
From: Brian D. <bde...@in...> - 2002-05-31 15:47:12
|
Hi Hoang/Thomas, A useful alternative that I have used for code generation is to use an XSLT style sheet to generate the interface and data object java code. Using the "Redirect" extension tag in Xalan, which can be used to redirect output to many different files, I do a transformation directly on the repository.xml into java source files. Additionally, because its a simple XSLT transformation, the code generation can be added as a "style" task in an ant build file, so that all classes are generated and compiled at build time. There's nothing else to code other than the stylesheet. I can send along mine as an example if you are interested. -Brian -- Brian DeVries Sr. Software Engineer mailto:bde...@in... http://www.intraware.com Voice: 925.253.6516 Fax: 925.253.6785 -------------------------------------------------------- Intraware... The leading provider of Electronic Software Delivery and Management (ESDM) Solutions |
From: Thomas M. <tho...@ho...> - 2002-05-31 19:50:23
|
Hi Brian, Brian Devries wrote: > Hi Hoang/Thomas, > > A useful alternative that I have used for code generation is to use an XSLT style > sheet to generate the interface and data object java code. Using the "Redirect" > extension tag in Xalan, which can be used to redirect output to many different > files, I do a transformation directly on the repository.xml into java source > files. > > Additionally, because its a simple XSLT transformation, the code generation can be > added as a "style" task in an ant build file, so that all classes are generated > and compiled at build time. cool! > > There's nothing else to code other than the stylesheet. I can send along mine as > an example if you are interested. > Yes, that is very interesting for us! thanks, Thomas > -Brian > > -- > Brian DeVries Sr. Software Engineer > mailto:bde...@in... http://www.intraware.com > Voice: 925.253.6516 Fax: 925.253.6785 > -------------------------------------------------------- > Intraware... The leading provider of Electronic Software > Delivery and Management (ESDM) Solutions > > > > _______________________________________________________________ > > Don't miss the 2002 Sprint PCS Application Developer's Conference > August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm > > _______________________________________________ > Objectbridge-developers mailing list > Obj...@li... > https://lists.sourceforge.net/lists/listinfo/objectbridge-developers > > > > |