Best practices for modularity?

View: New views
7 Messages — Rating Filter:   Alert me  

Best practices for modularity?

by polly.c.chang :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi everyone,

I'm back.  :)  I have been using EclipseLink for OXM, and it has succeeded extremely well for my prototype.  Thank you guys for all your help!  And congrats on the 1.0 release.  EclipseLink is awesome.  

Now I need to figure out a general strategy for using EclipseLink OXM in our enterprise.  I'm thinking that we will have some mappings that are considered "common" and then others that are application-specific and not shared.  The common vs. application mappings will be in different projects and deployed as different jars.  I can see that it's possible to partition the mappings from different projects so that they each have their own project.xml fiile, and then you can have one session.xml file that is able to work with multiple projects.xml files (we want to define as much as we can in the project xml files for easier maintenance).

My questions are:

1.  What does it mean to have a "primary" project versus "additional" projects in the session?  The documentation talks about how to configure these but doesn't really go into the ramifications.  Does the order of the projects matter?

2.  Is is possible for an application's mappings to override the ones from the common project?

3.  Is is possible for the common project to define mappings that are "abstract" or based on interfaces?  I see that there is an XMLChoiceMapping, but I am not sure how to use that because I won't know ahead of time what application-specific class I need to use.  I would like to have a common POJO that contains composite objects that are defined in the application-specific project.  Is that possible?

4.  Is is possible to map different root elements to the same POJO?  Or can I use a regular expression when matching the root element name?  Our schema is defined such that we have root elements with different names that have very similar content, so I'd like to be able to map them to the same POJO.  From what I've seen from the code, it looks like I will not be able to do this directly.  So I think my alternative is to come up with a transformation to apply before unmarshalling and after marshalling to change the root element name.  Or do you have other suggestions?

5.  Can you share any other best practices for implementing a modular design with these mappings?

Thanks for your help!

Polly

Re: Best practices for modularity?

by polly.c.chang :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Does anybody know the answers?  I tried hacking some stuff together but haven't met any success.  I really need the answers to 3 and 4 the most.

Thanks,
Polly


amphoras wrote:
Hi everyone,

I'm back.  :)  I have been using EclipseLink for OXM, and it has succeeded extremely well for my prototype.  Thank you guys for all your help!  And congrats on the 1.0 release.  EclipseLink is awesome.  

Now I need to figure out a general strategy for using EclipseLink OXM in our enterprise.  I'm thinking that we will have some mappings that are considered "common" and then others that are application-specific and not shared.  The common vs. application mappings will be in different projects and deployed as different jars.  I can see that it's possible to partition the mappings from different projects so that they each have their own project.xml fiile, and then you can have one session.xml file that is able to work with multiple projects.xml files (we want to define as much as we can in the project xml files for easier maintenance).

My questions are:

1.  What does it mean to have a "primary" project versus "additional" projects in the session?  The documentation talks about how to configure these but doesn't really go into the ramifications.  Does the order of the projects matter?

2.  Is is possible for an application's mappings to override the ones from the common project?

3.  Is is possible for the common project to define mappings that are "abstract" or based on interfaces?  I see that there is an XMLChoiceMapping, but I am not sure how to use that because I won't know ahead of time what application-specific class I need to use.  I would like to have a common POJO that contains composite objects that are defined in the application-specific project.  Is that possible?

4.  Is is possible to map different root elements to the same POJO?  Or can I use a regular expression when matching the root element name?  Our schema is defined such that we have root elements with different names that have very similar content, so I'd like to be able to map them to the same POJO.  From what I've seen from the code, it looks like I will not be able to do this directly.  So I think my alternative is to come up with a transformation to apply before unmarshalling and after marshalling to change the root element name.  Or do you have other suggestions?

5.  Can you share any other best practices for implementing a modular design with these mappings?

Thanks for your help!

Polly

Re: Best practices for modularity?

by Blaise Doughan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Polly,

I'm glad to hear you are enjoying your experience with EclipseLink, in particular the OXM mapping.  Below is my first stab at an answer based on some things we have done in the past. 

1.  What does it mean to have a "primary" project versus "additional"
projects in the session?  The documentation talks about how to configure
these but doesn't really go into the ramifications.  Does the order of the
projects matter?

I never really thought of it as primary vs additional projects.  Each project is equal, the order is only significant if you have multiple objects mapped to the same default root element.  As a default root element must correspond to only one descriptor.

---
2.  Is is possible for an application's mappings to override the ones from
the common project?
I'll describe a strategy we use to unmarshal our own metadata.  We use the Java version of the metadata  and create a subclass of the project for each version that we distribute.  Each descriptor is built in its own method, and when new features are added the corresponding mapping project overrides the corresponding buildDescriptor method.

In Root Project

public RootProject() {
    super();
    this.addDescriptor(buildFooDescriptor);
}

protected XMLDescriptor buildFooDescriptor() {
    XMLDescriptor fooDescriptor = new XMLDescriptor();
    // set up the descriptor
    return fooDescriptor;
}

In Child Project (Which Extends Root Project)

protected XMLDescriptor buildFooDescriptor() {
    XMLDescriptor fooDescriptor = super.buildFooDescriptor();
    // add to the descriptor
    return fooDescriptor;
}

This strategy is demonstrated in the EclipseLink source code in the following classes:

org.eclipse.persistence.internal.sessions.factories.ObjectPersistenceRuntimeXMLProject.java
org.eclipse.persistence.internal.sessions.factories.ObjectPersistenceRuntimeXMLProject_11_1_1.java
org.eclipse.persistence.internal.sessions.factories.EclipseLinkObjectPersistenceRuntimeXMLProject.java

---

3.  Is is possible for the common project to define mappings that are
"abstract" or based on interfaces?  I see that there is an
XMLChoiceMapping, but I am not sure how to use that because I won't know
ahead of time what application-specific class I need to use.  I would like
to have a common POJO that contains composite objects that are defined in
the application-specific project.  Is that possible?
I have seen users make use of our Any mappings for this.  Their scenario is usually the following, they have one OXM project that corresponds to the message envelope, and many OXM projects that correspond to possible payloads.  To implement this they use an XMLAnyObjectMapping to map the message body property on their message object, and then in the payload projects they ensure that all of objects that form the root of the body have default root elements set.  You will need to ensure that the XMLContext is created with both the message and payload projects.

---

4.  Is is possible to map different root elements to the same POJO?  Or
can I use a regular expression when matching the root element name?  Our
schema is defined such that we have root elements with different names
that have very similar content, so I'd like to be able to map them to the
same POJO.  From what I've seen from the code, it looks like I will not be
able to do this directly.  So I think my alternative is to come up with a
transformation to apply before unmarshalling and after marshalling to
change the root element name.  Or do you have other suggestions?
You can map multiple root elements to the same POJO.  Currently this can not be done in the UI, but you can create an "After Load" method and modify the descriptor by hand.  You can call "setDefaultRootElement(String)" multiple times on the descriptor.  All of these names will be used to recognize the object during unmarshalling, but the last defaultRootElement set will be used for marshalling.  If you want to use a different root element, you can wrap your object in an instance of org.eclipse.persistence.oxm.XMLRoot of javax.xml.bind.JAXBElement (if your are using JAXB).

---
5.  Can you share any other best practices for implementing a modular
design with these mappings?
I mentioned a couple of our most common strategies above.  Can you share more details about the type of modularity you would like to see?

-Blaise

amphoras wrote:
Does anybody know the answers?  I tried hacking some stuff together but
haven't met any success.  I really need the answers to 3 and 4 the most.

Thanks,
Polly



amphoras wrote:
  
Hi everyone,

I'm back.  :)  I have been using EclipseLink for OXM, and it has succeeded
extremely well for my prototype.  Thank you guys for all your help!  And
congrats on the 1.0 release.  EclipseLink is awesome.  

Now I need to figure out a general strategy for using EclipseLink OXM in
our enterprise.  I'm thinking that we will have some mappings that are
considered "common" and then others that are application-specific and not
shared.  The common vs. application mappings will be in different projects
and deployed as different jars.  I can see that it's possible to partition
the mappings from different projects so that they each have their own
project.xml fiile, and then you can have one session.xml file that is able
to work with multiple projects.xml files (we want to define as much as we
can in the project xml files for easier maintenance).

My questions are:

1.  What does it mean to have a "primary" project versus "additional"
projects in the session?  The documentation talks about how to configure
these but doesn't really go into the ramifications.  Does the order of the
projects matter?

2.  Is is possible for an application's mappings to override the ones from
the common project?

3.  Is is possible for the common project to define mappings that are
"abstract" or based on interfaces?  I see that there is an
XMLChoiceMapping, but I am not sure how to use that because I won't know
ahead of time what application-specific class I need to use.  I would like
to have a common POJO that contains composite objects that are defined in
the application-specific project.  Is that possible?

4.  Is is possible to map different root elements to the same POJO?  Or
can I use a regular expression when matching the root element name?  Our
schema is defined such that we have root elements with different names
that have very similar content, so I'd like to be able to map them to the
same POJO.  From what I've seen from the code, it looks like I will not be
able to do this directly.  So I think my alternative is to come up with a
transformation to apply before unmarshalling and after marshalling to
change the root element name.  Or do you have other suggestions?

5.  Can you share any other best practices for implementing a modular
design with these mappings?

Thanks for your help!

Polly


    

  

_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Re: Best practices for modularity?

by polly.c.chang :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Blaise,

Thanks for your detailed and helpful response.  I just have a few more questions.

> > 1.  What does it mean to have a "primary" project versus "additional"
> > projects in the session?  The documentation talks about how to configure
> > these but doesn't really go into the ramifications.  Does the order of the
> > projects matter?

> I never really thought of it as primary vs additional projects.  Each project is equal, the order is only
> significant if you have multiple objects mapped to the same default root element.  As a default root
> element must correspond to only one descriptor.

What I was trying to do was create an incomplete/abstract mapping for a class in my "common" project.xml file.  Then I created another mapping for the same class in my "app" project.xml file that fills in the missing pieces and overrides certain settings from the "common" mapping.  My session.xml file loads both project files.  

I found that since both mappings are for the same class, whichever one that I set as the "primary" in the session was wiped out by the second one.  Actually, all settings were replaced except for one.  The "common" and "app" versions of the class mappings have different "default root element" settings, and I found that both were available for unmarshalling.  So the result was cumulative.  It sounds like you expect that the default root element should have been replaced by the second class mapping?

---

> > 2.  Is is possible for an application's mappings to override the ones from
> > the common project?

> I'll describe a strategy we use to unmarshal our own metadata.  We use
> the Java version of the metadata  and create a subclass of the project
> for each version that we distribute.  Each descriptor is built in its
> own method, and when new features are added the corresponding mapping
> project overrides the corresponding buildDescriptor method.
> ...

yes, that is the exact behavior that I'm looking for!  Is it possible to do this using the deployment project.xml files?  I am trying to do as much as I can using the xml files.  I am ok with creating event listeners like the amendment method, but I am trying to minimize use of Java for ease of changing the mappings.

---

> > 3.  Is is possible for the common project to define mappings that are
> > "abstract" or based on interfaces?  I see that there is an
> > XMLChoiceMapping, but I am not sure how to use that because I won't know
> > ahead of time what application-specific class I need to use.  I would like
> > to have a common POJO that contains composite objects that are defined in
> > the application-specific project.  Is that possible?

> I have seen users make use of our Any mappings for this.  Their scenario
> is usually the following, they have one OXM project that corresponds to
> the message envelope, and many OXM projects that correspond to possible
> payloads.  To implement this they use an XMLAnyObjectMapping to map the
> message body property on their message object, and then in the payload
> projects they ensure that all of objects that form the root of the body
> have default root elements set.  You will need to ensure that the
> XMLContext is created with both the message and payload projects.

yes, exactly.  I have an element like this:

<Foo>
    <Action></Action>
    <Data></Data>
    <Data></Data>
    ...
</Foo>

"Action" is a class hierarchy of different kinds of actions, and "Data" is a collection of any type of element.  So I configured "Action" with an XMLChoiceMapping and "Data" as XMLAnyCollectionMapping, and that works!  I did try to set "Action" to XMLAnyObjectMapping, but EclipseLink got confused.  So I guess you can't use two "any" mappings next to one another, which makes sense.  The XMLChoiceMapping works fine for the "Action".

The only problem is when I try to go roundtrip more than once.  I can unmarshall the document and marshall it back out, but the Action element is output with the attribute 'xsi:type="ns1:ProcessType"'.  I don't think this attribute is allowed by the schema, and when I unmarshall the document again, I get:

[Fatal Error] :178:72: The prefix "xsi" for attribute "xsi:type" associated with an element type "ns1:Process" is not bound.

I noticed that the "xsi" namespace is not defined in the output file even though it was in the original one.  So my questions are:

a.  Can I suppress the xsi:type attribute from being generated?
b.  Failing that, I need to get this attribute added to the schema, correct?  
c.  How do I get the "xsi" namespace to be generated for the output?

---

> > 4.  Is is possible to map different root elements to the same POJO?  Or
> > can I use a regular expression when matching the root element name?  Our
> > schema is defined such that we have root elements with different names
> > that have very similar content, so I'd like to be able to map them to the
> > same POJO.  From what I've seen from the code, it looks like I will not be
> > able to do this directly.  So I think my alternative is to come up with a
> > transformation to apply before unmarshalling and after marshalling to
> > change the root element name.  Or do you have other suggestions?

> You can map multiple root elements to the same POJO.  Currently this can
> not be done in the UI, but you can create an "After Load" method and
> modify the descriptor by hand.  You can call
> "setDefaultRootElement(String)" multiple times on the descriptor.  All
> of these names will be used to recognize the object during
> unmarshalling, but the last defaultRootElement set will be used for
> marshalling.  

Hmm, my scenario is that the class mapping is in the "common" project, and I won't know what the possible default root elements are ahead of time.  Only the "app" project will know that, and it needs to define multiple root elements (around 5).  So I cannot call setDefaultRootElement() from the amendment method while the "common" project is loading.  This is similar to the "data" element in question 3 that was solved by the "any" mapping.  I need to go roundtrip using these many root elements, so marshalling using the last defined root element also won't work.  

> If you want to use a different root element, you can wrap
> your object in an instance of org.eclipse.persistence.oxm.XMLRoot of
> javax.xml.bind.JAXBElement (if your are using JAXB).

can you clarify this?  I've never actually worked with JAXB directly.  So far I've been very happy to let EclipseLink hide JAXB under the covers.  ;)

If I can marshall to those different root elements using a callback method, that would be fine.  I can figure out what root element to use based on data inside the object.

Or... would the "preserve document" setting help in this case?

---

> > 5.  Can you share any other best practices for implementing a modular
> > design with these mappings?

> I mentioned a couple of our most common strategies above.  Can you share
> more details about the type of modularity you would like to see?

sure, I'll summarize from my response above:
* ability to allow the project.xml files to inherit and override mappings like you are doing with Java.
* ability to defer defining root elements to another project.xml file.  
* ability to marshall using different root elements using a callback method or some way to "remember" what was unmarshalled.

Thanks for your help!  This is much easier than debugging random EclipseLink source code in hope of finding a hint.  :)

--Polly

Re: Best practices for modularity?

by polly.c.chang :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Blaise,

Blaise Doughan wrote:
If you want to use a different root element, you can wrap
your object in an instance of org.eclipse.persistence.oxm.XMLRoot of
javax.xml.bind.JAXBElement (if your are using JAXB).
OK, I Googled the JAXB API and experimented.  I think you're saying that I need to do this:

    public Object fromXML(final File file) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(MyGenericObject.class.getPackage().getName());
        Unmarshaller u = jc.createUnmarshaller();
   
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(file);
        Element  rootElem = doc.getDocumentElement();

        JAXBElement<MyGenericObject> jaxbElem = u.unmarshal( rootElem, MyGenericObject.class);
        return jaxbElem.getValue();
    }
   
    public String toXML(final MyGenericObject obj) throws Exception {        
        JAXBContext jc = JAXBContext.newInstance(MyGenericObject.class.getPackage().getName());
        Marshaller m = jc.createMarshaller();
        JAXBElement jaxbElem = new JAXBElement(
         new QName("http://www.foo.com/bar/baz","RootNodeFoo"),
         MyGenericObject.class, obj);
        StringWriter writer = new StringWriter();
        m.marshal(jaxbElem, writer );
        return writer.toString();
    }

Is that right?  This seems a bit messy.  It's not nearly as elegant as the generic marshalling and unmarshalling code that I'm able to use with EclipseLink.  :(  Is this what you recommend?

Thanks,
Polly

Re: Best practices for modularity?

by Blaise Doughan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Polly,

I'm going to try and develop this a little more but here are some current thoughts:

We use MOXy to map our XML mapping data to our programmatic metadata.  This means that you could use MOXy to unmarshal your XML metadata files into the programmatic metadata:

    import java.io.File;
    import org.eclipse.persistence.internal.sessions.factories.EclipseLinkObjectPersistenceRuntimeXMLProject;
    import org.eclipse.persistence.oxm.*;
    import org.eclipse.persistence.sessions.Project;
    ...
    EclipseLinkObjectPersistenceRuntimeXMLProject project = new EclipseLinkObjectPersistenceRuntimeXMLProject();
    XMLContext xmlContext = new XMLContext(project);

    XMLUnmarshaller unmarshaller = xmlContext.createUnmarshaller();
    Project baseProject = (Project) unmarshaller.unmarshal(new File("your_base_metadata.xml"));
    Project extensionProject = (Project) unmarshaller.unmarshal(new File("your_extension_metadata.xml"));

Then you could pull data from extensionProject into the baseProject, useful methods here are the following:

    XMLDescriptor customerDescriptor = (XMLDescriptor) project.getClassDescriptor(Customer.class);
    XMLDirectMapping firstNameMapping = (XMLDirectMapping) customerDescriptor.getMappingForAttributeName("firstName");

Finally you would create an XMLContext on your combined project, if you moved everything into your base project, then this would be done as follows:

    XMLContext xmlContext2 = new XMLContext(baseProject);

---

Other Items:
  • You are correct you can not use multiple Any mappings at the same level.
  • To get the xsi prefix to appear in the out document, in the UI be sure that in the schemas panel it is selected as a declaration to be included, or programmatically add it to the NamespaceResolver held onto by the descriptor.

-Blaise

amphoras wrote:
Hi Blaise,

Thanks for your detailed and helpful response.  I just have a few more
questions.

  
1.  What does it mean to have a "primary" project versus "additional"
projects in the session?  The documentation talks about how to configure
these but doesn't really go into the ramifications.  Does the order of
      
the
    
projects matter?
      

  
I never really thought of it as primary vs additional projects.  Each
project is equal, the order is only 
significant if you have multiple objects mapped to the same default root
element.  As a default root 
element must correspond to only one descriptor.
    

What I was trying to do was create an incomplete/abstract mapping for a
class in my "common" project.xml file.  Then I created another mapping for
the same class in my "app" project.xml file that fills in the missing pieces
and overrides certain settings from the "common" mapping.  My session.xml
file loads both project files.  

I found that since both mappings are for the same class, whichever one that
I set as the "primary" in the session was wiped out by the second one. 
Actually, all settings were replaced except for one.  The "common" and "app"
versions of the class mappings have different "default root element"
settings, and I found that both were available for unmarshalling.  So the
result was cumulative.  It sounds like you expect that the default root
element should have been replaced by the second class mapping?

---

  
2.  Is is possible for an application's mappings to override the ones
      
from
    
the common project?
      

  
I'll describe a strategy we use to unmarshal our own metadata.  We use 
the Java version of the metadata  and create a subclass of the project 
for each version that we distribute.  Each descriptor is built in its 
own method, and when new features are added the corresponding mapping 
project overrides the corresponding buildDescriptor method.
...
    

yes, that is the exact behavior that I'm looking for!  Is it possible to do
this using the deployment project.xml files?  I am trying to do as much as I
can using the xml files.  I am ok with creating event listeners like the
amendment method, but I am trying to minimize use of Java for ease of
changing the mappings.

---

  
3.  Is is possible for the common project to define mappings that are
"abstract" or based on interfaces?  I see that there is an
XMLChoiceMapping, but I am not sure how to use that because I won't know
ahead of time what application-specific class I need to use.  I would
      
like
    
to have a common POJO that contains composite objects that are defined
      
in
    
the application-specific project.  Is that possible?
      

  
I have seen users make use of our Any mappings for this.  Their scenario 
is usually the following, they have one OXM project that corresponds to 
the message envelope, and many OXM projects that correspond to possible 
payloads.  To implement this they use an XMLAnyObjectMapping to map the 
message body property on their message object, and then in the payload 
projects they ensure that all of objects that form the root of the body 
have default root elements set.  You will need to ensure that the 
XMLContext is created with both the message and payload projects.
    

yes, exactly.  I have an element like this:

<Foo>
    <Action></Action>
    <Data></Data>
    <Data></Data>
    ...
</Foo>

"Action" is a class hierarchy of different kinds of actions, and "Data" is a
collection of any type of element.  So I configured "Action" with an
XMLChoiceMapping and "Data" as XMLAnyCollectionMapping, and that works!  I
did try to set "Action" to XMLAnyObjectMapping, but EclipseLink got
confused.  So I guess you can't use two "any" mappings next to one another,
which makes sense.  The XMLChoiceMapping works fine for the "Action".

The only problem is when I try to go roundtrip more than once.  I can
unmarshall the document and marshall it back out, but the Action element is
output with the attribute 'xsi:type="ns1:ProcessType"'.  I don't think this
attribute is allowed by the schema, and when I unmarshall the document
again, I get:

[Fatal Error] :178:72: The prefix "xsi" for attribute "xsi:type" associated
with an element type "ns1:Process" is not bound.

I noticed that the "xsi" namespace is not defined in the output file even
though it was in the original one.  So my questions are:

a.  Can I suppress the xsi:type attribute from being generated?
b.  Failing that, I need to get this attribute added to the schema, correct?  
c.  How do I get the "xsi" namespace to be generated for the output?

---

  
4.  Is is possible to map different root elements to the same POJO?  Or
can I use a regular expression when matching the root element name?  Our
schema is defined such that we have root elements with different names
that have very similar content, so I'd like to be able to map them to
      
the
    
same POJO.  From what I've seen from the code, it looks like I will not
      
be
    
able to do this directly.  So I think my alternative is to come up with
      
a
    
transformation to apply before unmarshalling and after marshalling to
change the root element name.  Or do you have other suggestions?
      

  
You can map multiple root elements to the same POJO.  Currently this can 
not be done in the UI, but you can create an "After Load" method and 
modify the descriptor by hand.  You can call 
"setDefaultRootElement(String)" multiple times on the descriptor.  All 
of these names will be used to recognize the object during 
unmarshalling, but the last defaultRootElement set will be used for 
marshalling.  
    

Hmm, my scenario is that the class mapping is in the "common" project, and I
won't know what the possible default root elements are ahead of time.  Only
the "app" project will know that, and it needs to define multiple root
elements (around 5).  So I cannot call setDefaultRootElement() from the
amendment method while the "common" project is loading.  This is similar to
the "data" element in question 3 that was solved by the "any" mapping.  I
need to go roundtrip using these many root elements, so marshalling using
the last defined root element also won't work.  

  
If you want to use a different root element, you can wrap 
your object in an instance of org.eclipse.persistence.oxm.XMLRoot of 
javax.xml.bind.JAXBElement (if your are using JAXB).
    

can you clarify this?  I've never actually worked with JAXB directly.  So
far I've been very happy to let EclipseLink hide JAXB under the covers.  ;)

If I can marshall to those different root elements using a callback method,
that would be fine.  I can figure out what root element to use based on data
inside the object.

Or... would the "preserve document" setting help in this case?

---

  
5.  Can you share any other best practices for implementing a modular
design with these mappings?
      

  
I mentioned a couple of our most common strategies above.  Can you share 
more details about the type of modularity you would like to see?
    

sure, I'll summarize from my response above:
* ability to allow the project.xml files to inherit and override mappings
like you are doing with Java.
* ability to defer defining root elements to another project.xml file.  
* ability to marshall using different root elements using a callback method
or some way to "remember" what was unmarshalled.

Thanks for your help!  This is much easier than debugging random EclipseLink
source code in hope of finding a hint.  :)

--Polly
  

_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Re: Best practices for modularity?

by polly.c.chang :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

ah, I see.  This is an interesting strategy.  It gives me a lot of food for thought, and I'll definitely keep it in mind.  

Thanks,
Polly

Blaise Doughan wrote:
Hi Polly,

I'm going to try and develop this a little more but here are some
current thoughts:

We use MOXy to map our XML mapping data to our programmatic metadata.  
This means that you could use MOXy to unmarshal your XML metadata files
into the programmatic metadata:

    import java.io.File;
    import
org.eclipse.persistence.internal.sessions.factories.EclipseLinkObjectPersistenceRuntimeXMLProject;
    import org.eclipse.persistence.oxm.*;
    import org.eclipse.persistence.sessions.Project;
    ...
    EclipseLinkObjectPersistenceRuntimeXMLProject project = new
EclipseLinkObjectPersistenceRuntimeXMLProject();
    XMLContext xmlContext = new XMLContext(project);

    XMLUnmarshaller unmarshaller = xmlContext.createUnmarshaller();
    Project baseProject = (Project) unmarshaller.unmarshal(new
File("your_base_metadata.xml"));
    Project extensionProject = (Project) unmarshaller.unmarshal(new
File("your_extension_metadata.xml"));

Then you could pull data from extensionProject into the baseProject,
useful methods here are the following:

    XMLDescriptor customerDescriptor = (XMLDescriptor)
project.getClassDescriptor(Customer.class);
    XMLDirectMapping firstNameMapping = (XMLDirectMapping)
customerDescriptor.getMappingForAttributeName("firstName");

Finally you would create an XMLContext on your combined project, if you
moved everything into your base project, then this would be done as follows:

    XMLContext xmlContext2 = new XMLContext(baseProject);

---

Other Items:

    * You are correct you can not use multiple Any mappings at the same
      level.
    * To get the xsi prefix to appear in the out document, in the UI be
      sure that in the schemas panel it is selected as a declaration to
      be included, or programmatically add it to the NamespaceResolver
      held onto by the descriptor.


-Blaise

amphoras wrote:
> Hi Blaise,
>
> Thanks for your detailed and helpful response.  I just have a few more
> questions.
>
>  
>>> 1.  What does it mean to have a "primary" project versus "additional"
>>> projects in the session?  The documentation talks about how to configure
>>> these but doesn't really go into the ramifications.  Does the order of
>>>      
>> the
>>    
>>> projects matter?
>>>      
>
>  
>> I never really thought of it as primary vs additional projects.  Each
>> project is equal, the order is only
>> significant if you have multiple objects mapped to the same default root
>> element.  As a default root
>> element must correspond to only one descriptor.
>>    
>
> What I was trying to do was create an incomplete/abstract mapping for a
> class in my "common" project.xml file.  Then I created another mapping for
> the same class in my "app" project.xml file that fills in the missing pieces
> and overrides certain settings from the "common" mapping.  My session.xml
> file loads both project files.  
>
> I found that since both mappings are for the same class, whichever one that
> I set as the "primary" in the session was wiped out by the second one.
> Actually, all settings were replaced except for one.  The "common" and "app"
> versions of the class mappings have different "default root element"
> settings, and I found that both were available for unmarshalling.  So the
> result was cumulative.  It sounds like you expect that the default root
> element should have been replaced by the second class mapping?
>
> ---
>
>  
>>> 2.  Is is possible for an application's mappings to override the ones
>>>      
>> from
>>    
>>> the common project?
>>>      
>
>  
>> I'll describe a strategy we use to unmarshal our own metadata.  We use
>> the Java version of the metadata  and create a subclass of the project
>> for each version that we distribute.  Each descriptor is built in its
>> own method, and when new features are added the corresponding mapping
>> project overrides the corresponding buildDescriptor method.
>> ...
>>    
>
> yes, that is the exact behavior that I'm looking for!  Is it possible to do
> this using the deployment project.xml files?  I am trying to do as much as I
> can using the xml files.  I am ok with creating event listeners like the
> amendment method, but I am trying to minimize use of Java for ease of
> changing the mappings.
>
> ---
>
>  
>>> 3.  Is is possible for the common project to define mappings that are
>>> "abstract" or based on interfaces?  I see that there is an
>>> XMLChoiceMapping, but I am not sure how to use that because I won't know
>>> ahead of time what application-specific class I need to use.  I would
>>>      
>> like
>>    
>>> to have a common POJO that contains composite objects that are defined
>>>      
>> in
>>    
>>> the application-specific project.  Is that possible?
>>>      
>
>  
>> I have seen users make use of our Any mappings for this.  Their scenario
>> is usually the following, they have one OXM project that corresponds to
>> the message envelope, and many OXM projects that correspond to possible
>> payloads.  To implement this they use an XMLAnyObjectMapping to map the
>> message body property on their message object, and then in the payload
>> projects they ensure that all of objects that form the root of the body
>> have default root elements set.  You will need to ensure that the
>> XMLContext is created with both the message and payload projects.
>>    
>
> yes, exactly.  I have an element like this:
>
> <Foo>
>     <Action></Action>
>     <Data></Data>
>     <Data></Data>
>     ...
> </Foo>
>
> "Action" is a class hierarchy of different kinds of actions, and "Data" is a
> collection of any type of element.  So I configured "Action" with an
> XMLChoiceMapping and "Data" as XMLAnyCollectionMapping, and that works!  I
> did try to set "Action" to XMLAnyObjectMapping, but EclipseLink got
> confused.  So I guess you can't use two "any" mappings next to one another,
> which makes sense.  The XMLChoiceMapping works fine for the "Action".
>
> The only problem is when I try to go roundtrip more than once.  I can
> unmarshall the document and marshall it back out, but the Action element is
> output with the attribute 'xsi:type="ns1:ProcessType"'.  I don't think this
> attribute is allowed by the schema, and when I unmarshall the document
> again, I get:
>
> [Fatal Error] :178:72: The prefix "xsi" for attribute "xsi:type" associated
> with an element type "ns1:Process" is not bound.
>
> I noticed that the "xsi" namespace is not defined in the output file even
> though it was in the original one.  So my questions are:
>
> a.  Can I suppress the xsi:type attribute from being generated?
> b.  Failing that, I need to get this attribute added to the schema, correct?  
> c.  How do I get the "xsi" namespace to be generated for the output?
>
> ---
>
>  
>>> 4.  Is is possible to map different root elements to the same POJO?  Or
>>> can I use a regular expression when matching the root element name?  Our
>>> schema is defined such that we have root elements with different names
>>> that have very similar content, so I'd like to be able to map them to
>>>      
>> the
>>    
>>> same POJO.  From what I've seen from the code, it looks like I will not
>>>      
>> be
>>    
>>> able to do this directly.  So I think my alternative is to come up with
>>>      
>> a
>>    
>>> transformation to apply before unmarshalling and after marshalling to
>>> change the root element name.  Or do you have other suggestions?
>>>      
>
>  
>> You can map multiple root elements to the same POJO.  Currently this can
>> not be done in the UI, but you can create an "After Load" method and
>> modify the descriptor by hand.  You can call
>> "setDefaultRootElement(String)" multiple times on the descriptor.  All
>> of these names will be used to recognize the object during
>> unmarshalling, but the last defaultRootElement set will be used for
>> marshalling.  
>>    
>
> Hmm, my scenario is that the class mapping is in the "common" project, and I
> won't know what the possible default root elements are ahead of time.  Only
> the "app" project will know that, and it needs to define multiple root
> elements (around 5).  So I cannot call setDefaultRootElement() from the
> amendment method while the "common" project is loading.  This is similar to
> the "data" element in question 3 that was solved by the "any" mapping.  I
> need to go roundtrip using these many root elements, so marshalling using
> the last defined root element also won't work.  
>
>  
>> If you want to use a different root element, you can wrap
>> your object in an instance of org.eclipse.persistence.oxm.XMLRoot of
>> javax.xml.bind.JAXBElement (if your are using JAXB).
>>    
>
> can you clarify this?  I've never actually worked with JAXB directly.  So
> far I've been very happy to let EclipseLink hide JAXB under the covers.  ;)
>
> If I can marshall to those different root elements using a callback method,
> that would be fine.  I can figure out what root element to use based on data
> inside the object.
>
> Or... would the "preserve document" setting help in this case?
>
> ---
>
>  
>>> 5.  Can you share any other best practices for implementing a modular
>>> design with these mappings?
>>>      
>
>  
>> I mentioned a couple of our most common strategies above.  Can you share
>> more details about the type of modularity you would like to see?
>>    
>
> sure, I'll summarize from my response above:
> * ability to allow the project.xml files to inherit and override mappings
> like you are doing with Java.
> * ability to defer defining root elements to another project.xml file.  
> * ability to marshall using different root elements using a callback method
> or some way to "remember" what was unmarshalled.
>
> Thanks for your help!  This is much easier than debugging random EclipseLink
> source code in hope of finding a hint.  :)
>
> --Polly
>  

_______________________________________________
eclipselink-users mailing list
eclipselink-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/eclipselink-users