@JsonbPropertyOrder is now applied on property read name instead of a bean name. (#167)

Signed-off-by: Roman Grigoriadi <roman.grigoriadi@oracle.com>
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassParser.java b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
index 25b1069..540c9c3 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
@@ -34,8 +34,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 import java.util.Objects;
 
+
 /**
  * Created a class internal model.
  *
@@ -65,16 +67,29 @@
         parseClassAndInterfaceMethods(classElement, classProperties);
 
         //add sorted properties from parent, if they are not overridden in current class
-        final List<PropertyModel> sortedProperties = getSortedParentProperties(classModel, classElement, classProperties);
-        //sort and add properties from current class
-        sortedProperties.addAll(jsonbContext.getConfigProperties().getPropertyOrdering().orderProperties(classProperties, classModel, jsonbContext));
+        //parent properties are by default first by alphabet, than properties from a subclass
+        final List<PropertyModel> sortedParentProperties = getSortedParentProperties(classModel, classElement, classProperties);
 
-        checkPropertyNameClash(sortedProperties, classModel.getType());
+        List<PropertyModel> classPropertyModels = classProperties.values().stream()
+                .map(property -> new PropertyModel(classModel, property, jsonbContext))
+                .collect(Collectors.toList());
+
+        //check for collision on same property read name
+        List<PropertyModel> unsortedMerged = new ArrayList<>();
+        unsortedMerged.addAll(sortedParentProperties);
+        unsortedMerged.addAll(classPropertyModels);
+        checkPropertyNameClash(unsortedMerged, classModel.getType());
+
+
+        List<PropertyModel> sortedPropertyModels = new ArrayList<>();
+        sortedPropertyModels.addAll(sortedParentProperties);
+        sortedPropertyModels.addAll(jsonbContext.getConfigProperties().getPropertyOrdering()
+                .orderProperties(classPropertyModels, classModel));
 
         //reference property to creator parameter by name to merge configuration in runtime
         JsonbCreator creator = classModel.getClassCustomization().getCreator();
         if (creator != null) {
-            sortedProperties.forEach((propertyModel -> {
+            sortedPropertyModels.forEach((propertyModel -> {
                 for (CreatorModel creatorModel : creator.getParams()) {
                     if (creatorModel.getName().equals(propertyModel.getPropertyName())) {
                         CreatorCustomization customization = (CreatorCustomization) creatorModel.getCustomization();
@@ -83,7 +98,8 @@
                 }
             }));
         }
-        classModel.setProperties(sortedProperties);
+
+        classModel.setProperties(sortedPropertyModels);
 
     }
 
@@ -216,9 +232,9 @@
             for (PropertyModel checkedPropertyModel : checkedProperties) {
 
                 if ((checkedPropertyModel.getReadName().equals(collectedPropertyModel.getReadName())
-                && checkedPropertyModel.isReadable() && collectedPropertyModel.isReadable()) ||
+                        && checkedPropertyModel.isReadable() && collectedPropertyModel.isReadable()) ||
                         (checkedPropertyModel.getWriteName().equals(collectedPropertyModel.getWriteName()))
-                        && checkedPropertyModel.isWritable() && collectedPropertyModel.isWritable()) {
+                                && checkedPropertyModel.isWritable() && collectedPropertyModel.isWritable()) {
                     throw new JsonbException(Messages.getMessage(MessageKeys.PROPERTY_NAME_CLASH,
                             checkedPropertyModel.getPropertyName(), collectedPropertyModel.getPropertyName(),
                             cls.getName()));
@@ -232,13 +248,13 @@
      * Merges current class properties with parent class properties.
      * If javabean property is declared in more than one inheritance levels,
      * merge field, getters and setters of that property.
-     *
+     * <p>
      * For example BaseClass contains field foo and getter getFoo. In BaseExtensions there is a setter setFoo.
      * All three will be merged for BaseExtension.
-     *
+     * <p>
      * Such property is sorted based on where its getter or field is located.
      */
-    private  List<PropertyModel> getSortedParentProperties(ClassModel classModel, JsonbAnnotatedElement<Class<?>> classElement, Map<String, Property> classProperties) {
+    private List<PropertyModel> getSortedParentProperties(ClassModel classModel, JsonbAnnotatedElement<Class<?>> classElement, Map<String, Property> classProperties) {
         List<PropertyModel> sortedProperties = new ArrayList<>();
         //Pull properties from parent
         if (classModel.getParentClassModel() != null) {
@@ -280,10 +296,8 @@
      * <li> returns current otherwise</li>
      * </ul>
      *
-     *
      * @param current current 'child' implementation
      * @param parent  parent implementation
-     *
      * @return effective method to register as getter or setter
      */
     private Method selectMostSpecificNonDefaultMethod(Method current, Method parent) {
diff --git a/src/main/java/org/eclipse/yasson/internal/model/customization/ordering/PropertyOrdering.java b/src/main/java/org/eclipse/yasson/internal/model/customization/ordering/PropertyOrdering.java
index 912d8b1..31e0954 100644
--- a/src/main/java/org/eclipse/yasson/internal/model/customization/ordering/PropertyOrdering.java
+++ b/src/main/java/org/eclipse/yasson/internal/model/customization/ordering/PropertyOrdering.java
@@ -12,16 +12,16 @@
  ******************************************************************************/
 package org.eclipse.yasson.internal.model.customization.ordering;
 
-import org.eclipse.yasson.internal.JsonbContext;
 import org.eclipse.yasson.internal.model.ClassModel;
-import org.eclipse.yasson.internal.model.Property;
 import org.eclipse.yasson.internal.model.PropertyModel;
 
 import javax.json.bind.JsonbConfig;
 import javax.json.bind.config.PropertyOrderStrategy;
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * Order properties in bean object. {@link javax.json.bind.annotation.JsonbPropertyOrder} have always precedence.
@@ -49,30 +49,27 @@
      *
      * @param properties Properties to sort.
      * @param classModel Class model.
-     * @param jsonbContext jsonb context.
      * @return Sorted list of properties.
      */
-    public List<PropertyModel> orderProperties(Map<String, Property> properties, ClassModel classModel, JsonbContext jsonbContext) {
+    public List<PropertyModel> orderProperties(List<PropertyModel> properties, ClassModel classModel) {
+        Map<String, PropertyModel> byReadName = new HashMap<>();
+        properties.stream().forEach(propertyModel -> byReadName.put(propertyModel.getReadName(), propertyModel));
+
         String[] order = classModel.getClassCustomization().getPropertyOrder();
         List<PropertyModel> sortedProperties = new ArrayList<>();
         if (order != null) {
             //if @JsonbPropertyOrder annotation is defined on a class
             for (String propName : order) {
-                final Property remove = properties.remove(propName);
+                final PropertyModel remove = byReadName.remove(propName);
                 if (remove != null) {
-                    sortedProperties.add(new PropertyModel(classModel, remove, jsonbContext));
+                    sortedProperties.add(remove);
                 }
             }
         }
 
-        //No annotation or not ordered properties remains, check JsonbConfig for ordering strategy use LEXICOGRAPHICAL as default
-        return Stream.of(sortedProperties,
-                propertyOrderStrategy.sortProperties(
-                        properties.values().stream()
-                                .map((prop) -> new PropertyModel(classModel, prop, jsonbContext))
-                                .collect(Collectors.toList())))
-                .flatMap(Collection::stream)
-                .collect(Collectors.toList());
+        sortedProperties.addAll(propertyOrderStrategy.sortProperties(byReadName.values()));
+        return sortedProperties;
+
     }
 
     /**
diff --git a/src/test/java/org/eclipse/yasson/customization/PropertyOrderTest.java b/src/test/java/org/eclipse/yasson/customization/PropertyOrderTest.java
index 594d8ae..844f5e7 100644
--- a/src/test/java/org/eclipse/yasson/customization/PropertyOrderTest.java
+++ b/src/test/java/org/eclipse/yasson/customization/PropertyOrderTest.java
@@ -13,13 +13,21 @@
 
 package org.eclipse.yasson.customization;
 
-import org.eclipse.yasson.customization.model.*;
+import org.eclipse.yasson.customization.model.FieldCustomOrder;
+import org.eclipse.yasson.customization.model.FieldCustomOrderWrapper;
+import org.eclipse.yasson.customization.model.FieldOrder;
+import org.eclipse.yasson.customization.model.FieldOrderNameAnnotation;
+import org.eclipse.yasson.customization.model.FieldSpecificOrder;
+import org.eclipse.yasson.customization.model.RenamedPropertiesContainer;
 import org.junit.Assert;
 import org.junit.Test;
 
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbBuilder;
 import javax.json.bind.JsonbConfig;
+import javax.json.bind.annotation.JsonbCreator;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.annotation.JsonbPropertyOrder;
 import javax.json.bind.config.PropertyOrderStrategy;
 
 import static org.junit.Assert.assertEquals;
@@ -88,4 +96,34 @@
         RenamedPropertiesContainer unmarshalledObject = jsonb.fromJson("{ \"first\" : 1, \"second\" : \"Test String\", \"third\" : 1 }", RenamedPropertiesContainer.class);
         Assert.assertEquals(3, unmarshalledObject.getIntInstance());
     }
+
+    @Test
+    public void testJsonbPropertyOrderOnRenamedProperties() {
+        Jsonb jsonb = JsonbBuilder.create();
+        Assert.assertEquals("{\"from\":10,\"count\":11}", jsonb.toJson(new Range(10, 11)));
+    }
+
+    @JsonbPropertyOrder(
+            {
+                    "from",
+                    "count"
+            }
+    )
+    public class Range {
+
+        @JsonbProperty("from")
+        public final int fromIndex;
+
+        @JsonbProperty("count")
+        public final int numberOfItems;
+
+        @JsonbCreator
+        public Range(
+                @JsonbProperty("from") int fromIndex,
+                @JsonbProperty("count") int numberOfItems
+        ) {
+            this.fromIndex = fromIndex;
+            this. numberOfItems = numberOfItems;
+        }
+    }
 }