I have the below JSON code that needs to be parsed. I'm using the corresponding JAX-RS models. The problem is that the paymillClient object is null. If I add currency as a string inside the PaymillSubscription object, it returns EUR value, not null. So there appears to be a problem with the PaymillClient object, not plain strings. Could there be a limit to the number of nested objects for parsing ? Ex, max 2 nested objects. So because there are 3 in my case, it doesn't work.
Unfortunately, I cannot change the JSON code that needs to be parsed at all. I just need to make it work with the JAX-RS implementation.
{
"event":{
"event_type":"subscription.succeeded",
"event_resource":{
"subscription":{
"id":"sub_29f144a3bc32c71f96e2",
"offer":{ },
"livemode":false,
"amount":200,
"temp_amount":null,
"currency":"EUR",
"name":"Monthly subscription",
"interval":"1 MONTH",
"trial_start":null,
"trial_end":null,
"period_of_validity":null,
"end_of_period":null,
"next_capture_at":1428939744,
"created_at":1426264944,
"updated_at":1426264944,
"canceled_at":null,
"payment":{ },
"app_id":null,
"is_canceled":false,
"is_deleted":false,
"status":"active",
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
},
"transaction":{ }
},
"created_at":1426264944,
"app_id":null
}
}
PaymillEventContainer:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventContainer
{
private PaymillEvent event;
}
PaymillEvent:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEvent
{
#XmlElement(name = "event_type") #DocumentationExample(value = "subscription.succeeded") private String eventType;
#XmlElement(name = "event_resource") private PaymillEventResource eventResource;
}
PaymillEventResource:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventResource
{
private PaymillClient client;
private PaymillOffer offer;
private PaymillSubscription subscription;
}
PaymillSubscription:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillSubscription
{
private PaymillClient client;
private PaymillOffer offer;
}
PaymillClient:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillClient
{
#DocumentationExample(value = "client_c0c24aa7f97e1b8ed15d") private String id;
}
API endpoint code:
public Response postSubscriptionSucceeded(PaymillEventContainer paymillEventContainer)
{
PaymillEvent paymillEvent = paymillEventContainer.getPaymillEvent();
PaymillEventResource paymillEventResource = paymillEvent.getEventResource();
PaymillSubscription paymillSubscription = paymillEventResource.getSubscription();
PaymillClient paymillClient = paymillSubscription.getPaymillClient();
PaymillOffer paymillOffer = paymillSubscription.getPaymillOffer();
String clientId = paymillClient.getId(); // NullPointerException
}
Ok. I tried to run your code on your machine and also received null (note, that I'm using MOXy to unmarshall JSON). Then, I tried to experiment with it a little and found really funny things:
1. If you will remove all null-valued fields from your JSON, all works just perfect.
2. If you will add another field to PaymillSubscription. I added private Test test, where Test is:
#XmlAccessorType(XmlAccessType.FIELD)
public class Test {
private String id;
}
And will send this "test" object between last null-valued field in subscription object and "client" field:
"test":{"id":"sadas"},
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
Then "test" would be null, but "client" will be parsed as expected.
3. If you will add all null-valued objects into model (I mean, create respective fields in PaymillSubscription class) all works just perfect.
It seems, that by default JAXB specification doesn't allow JSON with unrecognized fields, but MOXy still tries to parse it (and sometimes produces errors).
Related
I'm struggling since a couple of hours trying to get MapStruct generate a valid mapper for JAXB generated classes. The particularity of these classes is that they don't have neither setters nor adders for collections. For example:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "IndividualType", propOrder = {"addressTypes","pensionTypes"})
public class IndividualType
{
...
#XmlElement(name = "addressType")
protected List<AddressType> addressTypes;
#XmlAttribute(name = "firstName", required = true)
protected String firstName;
...
public List<AddressType> getAddressTypes()
{
if (addressTypes == null) {
addressTypes = new ArrayList<AddressType>();
}
return this.addressTypes;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String value)
{
this.firstName = value;
}
...
}
The class avove have a getter and a setter for attributes (firstName in this example) but for collections (List here) it only has a getter. Hence it's the consumer responsibility to access via getAddressTypes(add (new AddressType(...)).
The MapStruct mapper for such a class is as follows:
#Mapper(collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE, uses = {AddressTypeMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE, componentModel = "spring")
public interface IndividualTypeMapper
{
IndividualType toIndividualType(IndividualEntity individual);
#InheritInverseConfiguration
IndividualEntity fromIndividualType(IndividualType individualType);
}
And the MapStruct generated code is:
#Override
public IndividualEntity fromIndividualType(IndividualType individualType)
{
if ( individualType == null )
return null;
IndividualEntity individualEntity = new IndividualEntity();
individualEntity.setFirstName( individualType.getFirstName() );
...
return individualEntity;
}
In the generated code above, only the properties having a setter get initialized despite the usage of the TARGET_IMMUTABLE strategy.
Any suggestions please ? Of course, a simple constructor would perfectly do but, for some reason, people seems to prefer complicated and nonworking solutions to simple working ones and, consequently, I have to use MapStruct :-(
Many thanks in advance.
Marie-France
The reason why it is not working is due to the fact that you are using CollectionMappingStrategy.TARGET_IMMUTABLE. With that you are basically telling MapStruct my collection targets are immutable and will throw an exception if you try to modify the collection returned by the getter.
I would suggest removing the collectionMappingStrategy and see whether it works without it.
Please find the below code for the DAO & Entity Object and Accessor
#Table(name = "Employee")
public class Employee {
#PartitionKey
#Column(name = "empname")
private String empname;
#ClusteringColumn(0)
#Column(name = "country")
private String country;
#Column(name = "status")
private String status;
}
Accessor:
#Accessor
public interface EmployeeAccessor {
#Query(value = "SELECT DISTINCT empname FROM EMPLOYEE ")
ResultSet getAllEmployeeName();
}
}
DAO getAllEmployeeNames returns a List which are employee names
and it will be sorted in ascending order.
DAO
public class EmployeeDAOImpl implements EmployeeDAO {
private EmployeeAccessor employeeAccessor;
#PostConstruct
public void init() {
employeeAccessor = datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);
}
#Override
public List<String> getAllEmployeeNames() {
List<Row> names = employeeAccessor.getAllEmployeeName().all();
List<String> empnames = names.stream()
.map(name -> name.getString("empname")).collect(Collectors.toList());
empnames.sort(naturalOrder()); //sorted
return empnames;
}
}
JUnit Test(mockito):
I am not able to mock the List[datastax row]. How to mock and returns a list of rows with values "foo" and "bar".Please help me in unit test this.
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class EmployeeDAOImplUnitTest {
#Mock
private ResultSet resultSet;
#Mock
private EmployeeAccessor empAccessor;
//here is the problem....how to mock the List<Row> Object --> com.datastax.driver.core.Row (interface)
//this code will result in compilation error as we are mapping a List<Row> to the ArrayList<String>
//how to mock the List<Row> with a list of String row object
private List<Row> unSortedTemplateNames = new ArrayList() {
{
add("foo");
add("bar");
}
};
//this is a test case to check if the results are sorted or not
//mock the accessor and send rows as "foo" & "bar"
//after calling the dao , the first element must be "bar" and not "foo"
#Test
public void shouldReturnSorted_getAllTemplateNames() {
when(empAccessor.getAllEmployeeName()).thenReturn(resultSet);
when(resultSet.all()).thenReturn(unSortedTemplateNames); //how to mock the List<Row> object ???
//i am testing if the results are sorted, first element should not be foo
assertThat(countryTemplates.get(0), is("bar"));
}
}
Wow! This is overly complex, hard to follow, and not an ideal way to write unit tests.
Using PowerMock(ito) along with "static" references in your own code is not recommended and is a sure sign of a code smells.
First, I am not sure why you decided to use a static reference (e.g. EmployeeAccessor.getAllEmployeeName().all(); inside the EmployeeDAOImpl class, getAllEmployeeNames() method) instead of using the instance variable (i.e. empAccessor), which is more conducive to actual "unit testing"?
The EmployeeAccessor, getAllEmployeeName() "interface" method is not static (clearly). However, seemingly, whatever this (datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class);) generates makes it so (really?), which then requires the use of PowerMock(ito), o.O
Frameworks like PowerMock, and extensions of (i.e. "PowerMockito"), were meant to test and mock code used by your application (unfortunately, but necessarily so) where this "other" code makes use of statics, Singletons, private methods and so on. This anti-pattern really ought not be followed in your own application design.
Second, it is not really apparent what the "Subject Under Test" (SUT) is in your test case. You implemented a test class (i.e. EmployeeDAOImplTest) for, supposedly, your EmployeeDAOImpl class (the actual "SUT"), but inside your test case (i.e. shouldReturnSorted_getAllTemplateNames()), you are calling... countryLocalizationDAOImpl.getAllTemplateNames(); thus testing the CountryLocalizationDAOImpl class (??), which is not the "SUT" of the EmployeeDAOImplTest class.
Additionally, it is not apparent that the EmployeeDAOImpl even uses a CountryLocalizationDAO instance (assuming an interface here as well), and if it does, then it is certainly something that should be "mocked" when the EmployeeDAOImpl "interacts" with instances of CountryLocalizationDAO, particularly in the context of a unit test. The only correlation between the EmployeeDAO and CountryLocalizationDAO is that the Employee has a country field.
There are a few other problems with your design/setup as well, but anyway.
Here are a few suggestions...
First, let's test what your EmployeeDAOImplTest is meant to test... EmployeeDAO.getAllEmployeeNames() in a sorted fashion. This in turn may give you ideas of how to test your "CountryLocalizationDAO, getAllTemplateNames() method perhaps (if it even makes sense, i.e. getAllTemplateNames() is in fact dependent on an Employee's country, when Employees are ordered by name (i.e. "empname" and accessed via EmployeeAccessor).
public class EmployeeDAOImpl implements EmployeeDAO {
private final EmployeeAccessor employeeAccessor;
// where does the DataStaxCassandraTemplate reference come from?!
private DataStaxCassadraTemplate datastaxCassandraTemplate = ...;
public EmployeeDAOImpl() {
this(datastaxCassandraTemplate.getAccessor(EmployeeAccessor.class));
}
public EmployeeDAOImpl(EmployeeAccessor employeeAccessor) {
this.employeeAccessor = employeeAccessor;
}
protected EmployeeAccessor getEmployeeAccessor() {
return this.empAccessor;
}
public List<String> getAllEployeeNames() {
List<Row> nameRows = getEmployeeAccessor().getAllEmployeeName().all();
...
}
}
Then in your test class...
public class EmployeeDAOImplUnitTest {
#Mock
private EmployeeAccessor mockEmployeeAccessor;
// SUT
private EmployeeDAO employeeDao;
#Before
public void setup() {
employeeDao = new EmployeeDAOImpl(mockEmployeeAccessor);
}
protected ResultSet mockResultSet(Row... rows) {
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.all()).thenReturn(Arrays.asList(rows));
return mockResultSet;
}
protected Row mockRow(String employeeName) {
Row mockRow = mock(Row.class, employeeName);
when(mockRow.getString(eq("empname")).thenReturn(employeeName);
return mockRow;
}
#Test
public void getAllEmployeeNamesReturnsSortListOfNames() {
when(mockEmployeeAccessor.getAllEmployeeName())
.thenReturn(mockResultSet(mockRow("jonDoe"), mockRow("janeDoe")));
assertThat(employeeDao.getAllEmployeeNames())
.contains("janeDoe", "jonDoe");
verify(mockEmployeeAccessor, times(1)).getAllEmployeeName();
}
}
Now, you can apply similar techniques if in fact there is an actual correlation between Employees and CountryLocalizationDAO via the EmployeeAccessor.
Hope this helps get you on a better track!
-j
My POJO:
public class Album{
private String title;
private Object tracks; // I can not change the type, beyond my control..
/** setter **/
....
/** getter **/
....
}
public class Track{
private String title;
private String singer;
/** setter **/
....
/** getter **/
....
}
Main method:
public static void main(String[] args)
{
Album album = new Album ();
album.setTitle("Thriller");
Track track = new Track();
track.setTitle("Beat It");
track.setSinger("M.J");
List<Track> trackLst = new ArrayList<Track>();
trackLst.add(track);
Album.setTracks(trackLst);
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, As.PROPERTY);
m.writeValue(System.out, album);
}
/** console printed **/
{
"title": "Thriller";
"tracks":[
"java.util.ArrayList",
[
{
"#class":"com.hs.Track",
"title":"Beat It",
"singer":"M.J"
}
]
]
}
As you can see, tracks serialized to a jsonArray, one element is the type(ArrayList), the other is the real jsonArray. Is there any solution that just keep the real jsonArray? like this:
{
"title": "Thriller";
"tracks":
[
{
"#class":"com.hs.Track",
"title":"Beat It",
"singer":"M.J"
}
]
}
The problem is type declaration private Object tracks, which causes property to match definition and force use of type information for the list as well. If it was declared as List<?>, this would not occur.
One thing you may be able to do is to use "mix-in annotations", to associate annotation like:
public class MixIn {
#JsonDeserialize(as=List.class)
#JsonSerialize(as=List.class)
private Object tracks;
}
and register mix-in to apply to class Album. This should indicate that intended type is List, and avoid inclusion of type information
I'm running a sample (which i can't find anymore) from Blaise Doughans blog on Glassfish 3 using EclipseLink 2.5 MOXy for JAXB service.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Company {
#XmlElementWrapper(name="employees")
#XmlElement(name = "employee", type=Employee.class)
private List<Employee> employees;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
private String id;
private String name;
}
I added some annotations to the classes, to produce the desired json structure:
{
"employees": [
{
"id": "1",
"name": "Jane Doe",
"report": []
}
]
}
When i try to unmarshal this JSON it sadly fails, returning an object with an empty employees list.
Adding another element to the JSON list OR removing the #XmlElementWrapper works.
But i want the key element to be named employees, so i have to use the wrapper annotation, or not?
Edit:
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(Index.class);
return set;
}
#Override
public Set<Object> getSingletons() {
MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
moxyJsonProvider.setAttributePrefix("#");
moxyJsonProvider.setFormattedOutput(true);
moxyJsonProvider.setIncludeRoot(false);
moxyJsonProvider.setMarshalEmptyCollections(true);
moxyJsonProvider.setValueWrapper("$");
moxyJsonProvider.setWrapperAsArrayName(true);
HashSet<Object> set = new HashSet<Object>(1);
set.add(moxyJsonProvider);
return set;
}
}
I have confirmed the issue that you are seeing and have opened the following bug:
http://bugs.eclipse.org/411001
UPDATE
The fix for this issue has been checked into the EclipseLink 2.5.1 and 2.6.0 streams. You can get the fix in the corresponding nightly builds from the following link starting June 19, 2013:
http://www.eclipse.org/eclipselink/downloads/nightly.php
I have a Object with two fields "name" and "address". JAXB ignores the empty elements while transforming the object into XMl.
For ex: if I have name="xyz" and address=null then out will be
<name>xyz</name>
but what I want as an output as
<name>xyz</name>
<address></address>
I have seen the option #XmlElement(nillable="true") but this gives the output as
<name>xyz</name>
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Please help me getting the desired output.
Thanks in advance.
A JAXB (JSR-222) implementation will output an empty String "" value as an empty element. You can set the address property to this to get the desired effect.
UPDATE #1
I have updated my question. Basically the address element is NULL. Is
this solution applicable to that as well?
You could leverage Marshal Event Callbacks to adjust the value of address.
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
private String address;
private void beforeMarshal(Marshaller marshaller) {
if(null == address) {
address = "";
}
}
private void afterMarshal(Marshaller marshaller) {
if("".equals(address)) {
address = null;
}
}
}
UPDATE #2
The only concern is that if I have 10 fields in the class I will have
to write if for all the fields. Is there any other solution?
If you use EclipseLink MOXy as your JAXB provider (I'm the MOXy lead), then you could use an XmlAdapter for this use case.
XmlAdapter (StringAdapter)
package forum14691333;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String string) throws Exception {
if(null == string) {
return "";
}
return string;
}
#Override
public String unmarshal(String string) throws Exception {
if("".equals(string)) {
return null;
}
return string;
}
}
package-info
Then if you specify it at the package level it will apply to all mapped fields/properties of type String within that package.
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
package forum14691333;
import javax.xml.bind.annotation.adapters.*;
For More Information
http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
If you use EclipseLink MOXy as your JAXB provider then you could use
#XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
#XmlElement(name = "address", nillable = true)
private String address;
By using this way, you don't have to write adapter for all the fields
Simply set an empty string default value on the field.
#XmlElement(required="true")
private String address = "";
and you will get
<address></address>