TestNG - Running same class with multiple threads in parallel - multithreading

Is there a way to run same class in parallel with multiple threads, like
<suite name="myTestSuite" verbose="1">
<test name="myTest" parallel="classes" thread-count="5">
<classes>
<class name="myPackage.Test" />
</classes>
</test>
</suite>
I want to the class 'myPackage.Test' to be invoked in 5 parallel threads.I know that it works if I want to executed different classes in parallel, like
<suite name="myTestSuite" verbose="1">
<test name="myTest" parallel="classes" thread-count="5">
<classes>
<class name="myPackage.Test1" />
<class name="myPackage.Test2" />
<class name="myPackage.Test3" />
<class name="myPackage.Test4" />
<class name="myPackage.Test5" />
</classes>
</test>
</suite>

As an alternate to the Factory pattern, you could create a <test> node for each time you want to run the class, then parallelize by test. You'd also want to move your parallelization attributes to the <suite> node. For example:
<suite name="mySuite" parallel="tests" thread-count="5">
<test name="myTest1">
<classes>
<class name="myPackage.Test" />
</classes>
</test>
<!-- Repeat the '<test>' node as many times as you wish to run the class -->
</suite>
You'll have to name each <test> uniquely, but this is decently simple way to run the same class many times and in parallel.

What you can do is using a Factory to create 5 instances of your test class.
public class TestFactory {
#Factory
public Object[] createInstances() {
Object[] result = new Object[5];
for (int i = 0; i < 5; i++) {
result[i] = new Test();
}
return result;
}
}
Then, you can use parallel="instances".
<suite name="myTestSuite" verbose="1">
<test name="myTest" parallel="instances" thread-count="5">
<classes>
<class name="myPackage.TestFactory"/>
</classes>
</test>
</suite>

Related

Add cucumber tags and feature file programmatically

I am using spring-boot cucumber with TestNG to write and API test framework ,
wanted to undersatand how can add tags and feature file to executed based on environment selected
Below is my current implementation
#CucumberOptions(
features = {"src/test/resources/Features"},
glue = {"als.system.tests.stepDefinations"},
plugin = {"pretty", "html:target/cucumber-html-report.html"}
)
public class CucumberRunnerTests extends AbstractTestNGCucumberTests {
}
And skipping test based on tags , but this is not ideal solution and also dont want to display skipped test on report
#Before
public void setup(Scenario scenario) {
if (!scenario.getSourceTagNames().contains("#" + productName.toLowerCase())) {
throw new SkipException("Skipping /Ignoring this scenario as not part of executions !!!");
}
}
Is there clean way to achieve this ?
Here's how you do it.
Ensure that you are using the latest released version of TestNG (it is 7.6.1 as of today and it needs JDK11)
Build a data provider interceptor by implementing the TestNG interface com.rationaleemotions.TagBasedInterceptor
Wire in this listener using either the <listener> tag (or) using the service provider interface approach. For details on this, you can refer to the official TestNG documentation here (or) refer to my blog-post here.
Below is a sample implementation of the listener
import io.cucumber.testng.PickleWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.testng.IDataProviderInterceptor;
import org.testng.IDataProviderMethod;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
public class TagBasedInterceptor implements IDataProviderInterceptor {
#Override
public Iterator<Object[]> intercept(Iterator<Object[]> original,
IDataProviderMethod dataProviderMethod, ITestNGMethod method, ITestContext iTestContext) {
String rawTag = iTestContext.getCurrentXmlTest().getParameter("tag");
if (rawTag == null || rawTag.trim().isEmpty()) {
return original;
}
List<String> tags = Arrays.asList(rawTag.trim().split(","));
List<Object[]> pruned = new ArrayList<>();
while (original.hasNext()) {
Object[] currentElement = original.next();
Optional<Object> searchResult = findPickleWrapper(currentElement);
if (searchResult.isEmpty()) {
continue;
}
PickleWrapper pickleWrapper = searchResult.map(element -> (PickleWrapper) element).get();
boolean tagPresent = pickleWrapper.getPickle().getTags()
.stream().anyMatch(tags::contains);
if (tagPresent) {
pruned.add(currentElement);
}
}
return pruned.iterator();
}
private Optional<Object> findPickleWrapper(Object[] each) {
return Arrays.stream(each)
.filter(element -> element instanceof PickleWrapper)
.findFirst();
}
}
Here's how the suite xml would look like
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Default Suite" verbose="2">
<listeners>
<listener class-name="com.rationaleemotions.TagBasedInterceptor"/>
</listeners>
<parameter name="tag" value="dragon_warrior"/>
<test name="testng_playground">
<classes>
<class name="com.rationaleemotions.CucumberRunnerTests">
</class>
</classes>
</test>
</suite>
Below are the dependencies that I am using for this sample
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>7.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.8.0</version>
</dependency>
</dependencies>
Feel free to enhance the listener such that if it also reads from the JVM argument (which you can specify using -D) so that you can have the dynamic behaviour of overriding the tag value in the suite xml with something that can be specified as a tag (or a comma separated list of tags) through the JVM argument.

Custom PatternLayoutConverter with log4net.Ext.Json?

I have the following log4net configuration:
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type='log4net.Layout.SerializedLayout, log4net.Ext.Json'>
<renderer type='log4net.ObjectRenderer.JsonDotNetRenderer, log4net.Ext.Json.Net'>
<DateFormatHandling value="IsoDateFormat" />
<NullValueHandling value="Ignore" />
</renderer>
<converter>
<name value="preparedMessage" />
<type value="JsonLogs.CustomLayoutConverter" />
</converter>
<default />
<remove value='message' />
<remove value='ndc' />
<member value='message:messageObject' />
<member value='details:preparedMessage' />
</layout>
</appender>
<appender name="Console2" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<converter>
<name value="preparedMessage" />
<type value="JsonLogs.CustomLayoutConverter" />
</converter>
<conversionPattern value="%level %thread %logger - %preparedMessage%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
<appender-ref ref="Console2" />
</root>
</log4net>
with the following implementation of my custom PatternLayoutConverter:
namespace JsonLogs
{
using System.IO;
using log4net.Core;
using log4net.Layout.Pattern;
public class CustomLayoutConverter : PatternLayoutConverter
{
#region Methods
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
if (loggingEvent.MessageObject is string stringMessage)
{
writer.Write(new { message = stringMessage });
}
else
{
writer.Write(loggingEvent.RenderedMessage);
}
}
#endregion
}
}
For some reason, the converter works perfectly fine with the Console2 appender(which is not JSON driven) but it doesn't work with the Console appender whose output is JSON.
Example of the output:
Console -> {"date":"2018-12-09T12:25:28.0529041+03:00","level":"INFO","appname":"JsonLogs.exe","logger":"JsonLogs.Program","thread":"1","message":"Test","details":"preparedMessage"}
Console2 -> INFO 1 JsonLogs.Program - { message = Test }
My goal is to have details always in JSON that's why I introduced my own converter to catch primitive values and wrap them in a custom object.
Is my configuration wrong? Or I'm missing something? Could you help me, please, to figure this out?
Thank you
The issue seems to be a bug of log4net.Ext.Json. I'm going to report it on their GitLab.
So far, I ended up with my custom log4net layout which looks like this
public class CustomLayout : PatternLayout
{
#region Public Methods and Operators
public override void Format(TextWriter writer, LoggingEvent loggingEvent)
{
var message = loggingEvent.MessageObject.GetType().IsPrimitive || loggingEvent.MessageObject is string || loggingEvent.MessageObject is decimal || loggingEvent.MessageObject is BigInteger
? new { message = loggingEvent.MessageObject }
: loggingEvent.MessageObject;
writer.WriteLine(JsonConvert.SerializeObject(new
{
timestamp = loggingEvent.TimeStampUtc,
threadId = loggingEvent.ThreadName,
details = message,
logger = loggingEvent.LoggerName,
level = loggingEvent.Level.DisplayName,
user = loggingEvent.UserName
}));
}
#endregion
}
it meets my needs and does exactly what I want.
The exact place of this problem is AddMember Method and its implementation. Here is SerializedLayout source code for that:
public virtual void AddMember(string value)
{
var arrangement = log4net.Util.TypeConverters.ArrangementConverter.GetArrangement(value, new ConverterInfo[0]);
m_arrangement.AddArrangement(arrangement);
}
As you can see the second parameter of GetArrangment is empty array of ConverterInfo, Though there must be our custom attached ones (by AddConverter method or by xml).
As the solution you can implement your own subclass that will derive from SerializedLayout with overridden AddMember like this:
public override void AddMember(string value)
{
var customConverter = new ConverterInfo("lookup", typeof(CustomPatternConverter));
var arrangement = log4net.Util.TypeConverters.ArrangementConverter.GetArrangement(value, new ConverterInfo[] { customConverter });
m_arrangement.AddArrangement(arrangement);
}
Hope it helps as it did with my case!

How to print logs using log4j in selenium webdriver

Environment:
Java, Selenium webdriver, Maven, testNG, Log4J, Eclipse
XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll" parallel = "tests" thread-count = "2">
<test name="postivelogintest_IE">
<parameter name="browser" value="ie"/>
<classes>
<class name="com.dice.LoginTest">
<methods>
<include name="DataDrivenpositiveLoginTest"/>
</methods>
</class>
</classes>
</test>
<test name="postivelogintest_CH">
<parameter name="browser" value="ch"/>
<classes>
<class name="com.dice.LoginTest">
<methods>
<include name="DataDrivenpositiveLoginTest"/>
</methods>
</class>
</classes>
</test>
</suite>
BaseTest.java
package com.diceBase;
import org.apache.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
public class BaseTest {
protected WebDriver driver;
protected Logger log;
#Parameters ({"browser"})
#BeforeMethod
protected void MethodSetup(String browser){
log.info("method set up"); // line 16
driver = BrowserFactory.getDriver(browser);
}
#AfterMethod
protected void TearDown(){
log.info("method tear down");
try {
Thread.sleep(5000);
driver.quit();
} catch (Exception e) {
}
}
}
I added log4j.properties under src/main/resources.
In the BaseTest.java, I added two lines after importing log4j.
log.info("method set up");
log.info("method tear down");
iMy goal is to be able to use log.info entire project. Before that, I would like to test it by only importing log4j logger in basetest class to see if it works. If it works then I can import log4j in entire project.
I get error if I keep both log messages. But, If I remove both log messages, script passes. How can I print the logs using log4j?
The log variable in your BaseTest.java has not assigned with object of logger class (https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Logger.html) . Since No object is assigned to the variable log, it throws NULL pointer exception. So please create object of logger class to varaiable log

How to create separate Log4j2 rolling file appenders and loggers programatically for multiple threads

I am running my TestNG tests on multiple threads (Appium tests on multiple devices simultaneously) and want to write the test logs on different threads in different files. Here the threads are created automatically before the start of the test flow.
So I want to create separate appender and separate logger programatically so that each appender would be attached to its own thread only and then the loggers created in one thread would have the appender created in that thread only.
Please let me know how to achieve it step by step.
First, this feels like an XY Problem especially because you have not provided any reasoning as to why you want to go with a programmatic solution.
It is possible to achieve separate log files on a thread by thread basis without programmatically creating loggers and appenders. Since I believe this to be a more optimal solution I will provide a demo of how it can be done.
Explanation
This solution will use the RoutingAppender and ThreadContext to create appenders for each Thread. The example that follows will use a simple FileAppender but you can swap in a RollingFileAppender very easily. Since you did not state that you have any requirement to use different log levels for each thread the following example will not implement this feature. Finally, the example will not use TestNG as it has some overhead to set up; instead a simple class with a main that creates two threads will be used.
Example Implementation
log4j2.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Routing name="MyRoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route>
<File
fileName="logs/${ctx:threadName}/log.txt"
name="appender-${ctx:threadName}">
<PatternLayout>
<Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="Thread" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="MyRoutingAppender" />
</Logger>
<Root level="WARN">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
Java class that generates logs using 2 concurrent threads:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class MultiThreadLog4j2SepFilesMain {
//Create a lock to use for synchronizing the getting of the logger
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable(){
public void run() {
//Set up the context before getting logger
ThreadContext.put("threadName", Thread.currentThread().getName());
//Get the logger for this thread
Logger log = null;
synchronized(lock){
log = LogManager.getLogger(Thread.currentThread().getName());
}
//Generate some logs
log.info("here's the first thread");
//Wait a while so that threads interleave
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Generate more logs
log.debug("some debug in first thread");
log.info("finishing first thread");
}}, "Thread.1"); //Use a name that will allow us to use Thread.getName when getting the logger inside the thread
Thread t2 = new Thread(new Runnable(){
public void run() {
//Set up the context before getting logger
ThreadContext.put("threadName", Thread.currentThread().getName());
//Get logger for this thread
Logger log = null;
synchronized(lock){
log = LogManager.getLogger(Thread.currentThread().getName());
}
//Generate some logs
log.info("here's the second thread");
log.debug("some debug in second thread");
}}, "Thread.2"); //Use a name that will allow us to use Thread.getName when getting the logger inside the thread
//Start both threads
t1.start();
t2.start();
}
}

Inheritance mapping throwing an exception with MOXy

I followed the second option mentioned in JAXB inheritance in MOXY to map my parent class and child class listed below. MOXy is throwing the below exception and not sure what the issue is
Parent class
public class UnitedStatesAddressData extends AbstractAddress implements UnitedStatesAddress, Serializable, Cloneable
{
private String primaryAddress;
public String getPrimaryAddress()
{
return primaryAddress;
}
public void setPrimaryAddress(final String primaryAddress)
{
this.primaryAddress = primaryAddress;
}
}
Child Class
public class TokenizedUnitedStatesAddressData extends UnitedStatesAddressData implements TokenizedUnitedStatesAddress,
CloneableAddress
{
private String houseNumber;
private String preDirectional;
private String streetName;
private String streetType;
//getters and setters ignored
}
external binding file
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.eclipse.org/eclipselink/xsds/persistence/oxm http://www.eclipse.org/eclipselink/xsds/eclipselink_oxm_2_4.xsd"
version="2.4" package-name="com.abc.ic.domain.impl.country.us" xml-accessor-type="PROPERTY">
<xml-schema element-form-default="QUALIFIED" namespace="http://xml.abc.com/XMLSchema/InterConnect">
<!-- Do not specify 'prefix'. We doesn't want the namespace prefix in our instance documents as they increase the payload size. -->
<xml-ns namespace-uri="http://xml.abc.com/XMLSchema/InterConnect" />
</xml-schema>
<java-types>
<java-type name="TokenizedUnitedStatesAddressData">
<xml-root-element name="USAddress" />
<xml-type prop-order="preDirectional houseNumber streetName streetType postDirection unitDesignator apartmentNumber primaryAddress secondaryAddress cityName stateAbbreviation zipCode" />
<java-attributes>
<xml-element name="StreetPreDirection" java-attribute="preDirectional" />
<xml-element name="StreetNumber" java-attribute="houseNumber" />
<xml-element name="StreetName" java-attribute="streetName" />
<xml-element name="StreetType" java-attribute="streetType" />
<xml-element name="StreetPostDirection" java-attribute="postDirection" />
<xml-element name="UnitDesignator" java-attribute="unitDesignator" />
<xml-element name="UnitNumber" java-attribute="apartmentNumber" />
<xml-element name="AddressLine1" java-attribute="primaryAddress" />
<xml-element name="AddressLine2" java-attribute="secondaryAddress" />
<xml-element name="City" java-attribute="cityName" />
<xml-element name="State" java-attribute="stateAbbreviation" />
<xml-element name="PostalCode" java-attribute="zipCode" />
</java-attributes>
</java-type>
<java-type name="UnitedStatesAddressData" xml-transient="true">
<xml-root-element />
</java-type>
</java-types>
</xml-bindings>
Error
javax.xml.bind.JAXBException:
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.
- with linked exception:
[Exception [EclipseLink-50009] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.JAXBException
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.]
at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:908)
at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:157)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:170)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:157)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:117)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:107)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:331)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at com.abc.ic.platform.sts.domain.transformation.response.JaxbTest.beforeClass(JaxbTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: Exception [EclipseLink-50009] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.JAXBException
Exception Description: The property or field primaryAddress is annotated to be transient so can not be included in the proporder annotation.
at org.eclipse.persistence.exceptions.JAXBException.transientInProporder(JAXBException.java:225)
at org.eclipse.persistence.jaxb.compiler.TypeInfo.setProperties(TypeInfo.java:342)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.buildTypeInfo(AnnotationsProcessor.java:755)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.postBuildTypeInfo(AnnotationsProcessor.java:669)
at org.eclipse.persistence.jaxb.compiler.XMLProcessor.processXML(XMLProcessor.java:344)
at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:145)
at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:904)
... 28 more
UPDATE
I've tested this by removing "prop-order" and this works fine except that I can no longer control the order of the elements in generated XML. I believe this is a bug in the code.
The cause for this is that the child class overrides the method from parent class as sown below but since the parent class has been defined to be xml-transient="true", the below check from TypeInfo is failing.
child class overriding getPrimaryAddress
public class TokenizedUnitedStatesAddressData extends UnitedStatesAddressData implements TokenizedUnitedStatesAddress,
CloneableAddress
{
#override
public String getPrimaryAddress()
{
return primaryAddress;
}
}
TypeInfo.java offending code
if (p.isTransient() && propOrderList.contains(p.getPropertyName()))
{
throw org.eclipse.persistence.exceptions.JAXBException.transientInProporder(p.getPropertyName());
}
UPDATE 2
The issue is not with the AbstractAddress. After some debugging, the issue seems to be with the below logic in the AnnotationProcessor.getPropertyPropertiesForClass(final JavaClass cls, final TypeInfo info, final boolean onlyPublic, final boolean onlyExplicit)
if ((setMethod == null) && !(hasJAXBAnnotations(getMethod)))
{
// if there's no corresponding setter, and not explicitly
// annotated, don't process
isPropertyTransient = true;
}
This method will tag any method that doesn't have both the get/set methods defined as "transient". In my case, I override just the getPrimaryAddress() method in TokenizedUnitedStatesAddressData class and not the corresponding setter. And hence the Annotationprocessor is designating it as a transient property neglecting the fact that this method is being overridden.
FIX
The issue is fixed after making sure that the overridden methods are properly handled in the transient check as shown below
if ((setMethod == null) && !(hasJAXBAnnotations(getMethod)))
{
if (!isMethodOverrriden(cls.getQualifiedName(), getMethod.getName()))
{
// if there's no corresponding setter, and not explicitly
// annotated, don't process
isPropertyTransient = true;
}
}
public static boolean isMethodOverrriden(final String classQualifiedName, final String methodName)
{
Method myMethod;
try
{
myMethod = Class.forName(classQualifiedName).getMethod(methodName, null);
}
catch (Exception e1)
{
return false;
}
Class<?> declaringClass = myMethod.getDeclaringClass();
if (declaringClass.equals(Object.class))
{
return false;
}
Class<?> superclass = declaringClass.getSuperclass();
if (superclass == null)
{
return false;
}
else
{
try
{
superclass.getMethod(myMethod.getName(), myMethod.getParameterTypes());
}
catch (NoSuchMethodException e)
{
// recursively check all super classes
isMethodOverrriden(superclass.getName(), methodName);
}
return true;
}
}
Even though you have marked UnitedStatesAddressData as #XmlTransient (using MOXy's external mapping document), it's super class AbstractAddress is still a mapped class. As such properties from AbstractAddress can not be specified in the propOrder setting for TokenizedUnitedStatesAddressData. The solution will be to make AbstractAddress #XmlTransient as well.
Fix
I have modified your mapping document to do this below assuming that the AbstractAddress class is in the same package as the rest of your domain model.
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.eclipse.org/eclipselink/xsds/persistence/oxm http://www.eclipse.org/eclipselink/xsds/eclipselink_oxm_2_4.xsd"
version="2.4" package-name="com.abc.ic.domain.impl.country.us" xml-accessor-type="PROPERTY">
<xml-schema element-form-default="QUALIFIED" namespace="http://xml.abc.com/XMLSchema/InterConnect">
<!-- Do not specify 'prefix'. We doesn't want the namespace prefix in our instance documents as they increase the payload size. -->
<xml-ns namespace-uri="http://xml.abc.com/XMLSchema/InterConnect" />
</xml-schema>
<java-types>
<java-type name="TokenizedUnitedStatesAddressData">
<xml-root-element name="USAddress" />
<xml-type prop-order="preDirectional houseNumber streetName streetType postDirection unitDesignator apartmentNumber primaryAddress secondaryAddress cityName stateAbbreviation zipCode" />
<java-attributes>
<xml-element name="StreetPreDirection" java-attribute="preDirectional" />
<xml-element name="StreetNumber" java-attribute="houseNumber" />
<xml-element name="StreetName" java-attribute="streetName" />
<xml-element name="StreetType" java-attribute="streetType" />
<xml-element name="StreetPostDirection" java-attribute="postDirection" />
<xml-element name="UnitDesignator" java-attribute="unitDesignator" />
<xml-element name="UnitNumber" java-attribute="apartmentNumber" />
<xml-element name="AddressLine1" java-attribute="primaryAddress" />
<xml-element name="AddressLine2" java-attribute="secondaryAddress" />
<xml-element name="City" java-attribute="cityName" />
<xml-element name="State" java-attribute="stateAbbreviation" />
<xml-element name="PostalCode" java-attribute="zipCode" />
</java-attributes>
</java-type>
<java-type name="UnitedStatesAddressData" xml-transient="true">
<xml-root-element />
</java-type>
<java-type name="AbstractAddress" xml-transient="true">
<xml-root-element />
</java-type>
</java-types>
</xml-bindings>
For More Information
http://blog.bdoughan.com/2012/08/jaxbs-xmltransient-and-property-order.html

Resources