« Return to Thread: Best practices for modularity?
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
« Return to Thread: Best practices for modularity?
| Free embeddable forum powered by Nabble | Forum Help |