Repository: johnzon
Updated Branches:
  refs/heads/master b28c4baa0 -> b3e496efc


JOHNZON-89 JOHNZON-88 switching default access mode to field+method + fixing 
this mode + upgrading tomee for websocket tests


Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/b3e496ef
Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/b3e496ef
Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/b3e496ef

Branch: refs/heads/master
Commit: b3e496efc6afead36a115979ef4c478a1cae4a53
Parents: b28c4ba
Author: Romain manni-Bucau <[email protected]>
Authored: Sat Jul 2 21:21:54 2016 +0200
Committer: Romain manni-Bucau <[email protected]>
Committed: Sat Jul 2 21:21:54 2016 +0200

----------------------------------------------------------------------
 .../apache/johnzon/jsonb/JsonbAccessMode.java   |   2 +-
 .../apache/johnzon/mapper/MapperBuilder.java    |   6 +-
 .../mapper/access/FieldAndMethodAccessMode.java | 140 +++++++++++++++++--
 .../johnzon/mapper/access/MethodAccessMode.java |  16 ++-
 .../johnzon/mapper/GetterSetterRespectTest.java |  49 +++++++
 .../johnzon/mapper/JohnzonAnyMappingTest.java   |   2 +
 johnzon-websocket/pom.xml                       |  18 ++-
 .../src/test/resources/arquillian.xml           |   1 -
 src/site/markdown/index.md                      |   2 +
 9 files changed, 210 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index 25bdf12..28c7211 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -127,7 +127,7 @@ public class JsonbAccessMode implements AccessMode, 
Closeable {
         this.order = orderValue;
         this.visibility = visibilityStrategy;
         this.caseSensitive = caseSensitive;
-        this.delegate = new FieldAndMethodAccessMode(true, true);
+        this.delegate = new FieldAndMethodAccessMode(true, true, false);
         this.defaultConverters = defaultConverters;
         this.factory = factory;
         this.parserFactory = parserFactory;

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index 944ed9b..b3e57eb 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -167,10 +167,10 @@ public class MapperBuilder {
                 accessMode = new MethodAccessMode(supportConstructors, 
supportHiddenAccess, true);
             } else if ("strict-method".equalsIgnoreCase(accessModeName)) {
                 accessMode = new MethodAccessMode(supportConstructors, 
supportHiddenAccess, false);
-            } else if ("both".equalsIgnoreCase(accessModeName)) {
-                accessMode = new FieldAndMethodAccessMode(supportConstructors, 
supportHiddenAccess);
+            } else if ("both".equalsIgnoreCase(accessModeName) || 
accessModeName == null) {
+                accessMode = new FieldAndMethodAccessMode(supportConstructors, 
supportHiddenAccess, useGetterForCollections);
             } else {
-                accessMode = new MethodAccessMode(supportConstructors, 
supportHiddenAccess, useGetterForCollections);
+                throw new IllegalArgumentException("Unsupported access mode: " 
+ accessModeName);
             }
         }
         if (!ignoredForFields.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
index 0e4d9e7..607bf2d 100644
--- 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
@@ -19,52 +19,174 @@
 package org.apache.johnzon.mapper.access;
 
 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.JohnzonIgnore;
+import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.ObjectConverter;
 
+import java.beans.Introspector;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.Map;
 
-// methods override fields
+// annotated entity overrides the other one, methods are used instead of field 
if both are there
 public class FieldAndMethodAccessMode extends BaseAccessMode {
     private final FieldAccessMode fields;
     private final MethodAccessMode methods;
 
-    public FieldAndMethodAccessMode(final boolean useConstructor, final 
boolean acceptHiddenConstructor) {
+    public FieldAndMethodAccessMode(final boolean useConstructor, final 
boolean acceptHiddenConstructor,
+                                    final boolean useGettersAsWriter) {
         super(useConstructor, acceptHiddenConstructor);
         this.fields = new FieldAccessMode(useConstructor, 
acceptHiddenConstructor);
-        this.methods = new MethodAccessMode(useConstructor, 
acceptHiddenConstructor, false);
+        this.methods = new MethodAccessMode(useConstructor, 
acceptHiddenConstructor, useGettersAsWriter);
     }
 
     @Override
     public Map<String, Reader> doFindReaders(final Class<?> clazz) {
-        final Map<String, Reader> readers = new HashMap<String, 
Reader>(fields.findReaders(clazz));
-        for (final Map.Entry<String, Reader> entry : 
methods.findReaders(clazz).entrySet()) {
+        final Map<String, Reader> fieldsReaders = 
this.fields.findReaders(clazz);
+        final Map<String, Reader> methodReaders = 
this.methods.findReaders(clazz);
+
+        final Map<String, Reader> readers = new HashMap<String, Reader>();
+
+        for (final Map.Entry<String, Reader> entry : fieldsReaders.entrySet()) 
{
+            final String key = entry.getKey();
+            Method m = getMethod("get" + Character.toUpperCase(key.charAt(0)) 
+ (key.length() > 1 ? key.substring(1) : ""), clazz);
+            if (m == null && (boolean.class == entry.getValue().getType() || 
Boolean.class == entry.getValue().getType())) {
+                m = getMethod("is" + Character.toUpperCase(key.charAt(0)) + 
(key.length() > 1 ? key.substring(1) : ""), clazz);
+            }
+            boolean skip = false;
+            if (m != null) {
+                for (final Reader w : methodReaders.values()) {
+                    if 
(MethodAccessMode.MethodDecoratedType.class.cast(w).getMethod().equals(m)) {
+                        if (w.getAnnotation(JohnzonProperty.class) != null || 
w.getAnnotation(JohnzonIgnore.class) != null) {
+                            skip = true;
+                        }
+                        break;
+                    }
+                }
+            }
+            if (skip) {
+                continue;
+            }
+            readers.put(entry.getKey(), entry.getValue());
+        }
+
+        for (final Map.Entry<String, Reader> entry : methodReaders.entrySet()) 
{
+            final Method mr = 
MethodAccessMode.MethodDecoratedType.class.cast(entry.getValue()).getMethod();
+            final String fieldName = 
Introspector.decapitalize(mr.getName().startsWith("is") ? 
mr.getName().substring(2) : mr.getName().substring(3));
+            final Field f = getField(fieldName, clazz);
+            boolean skip = false;
+            if (f != null) {
+                for (final Reader w : fieldsReaders.values()) {
+                    if 
(FieldAccessMode.FieldDecoratedType.class.cast(w).getField().equals(f)) {
+                        if (w.getAnnotation(JohnzonProperty.class) != null || 
w.getAnnotation(JohnzonIgnore.class) != null) {
+                            skip = true;
+                        }
+                        break;
+                    }
+                }
+            }
+            if (skip) {
+                continue;
+            }
+
             final Reader existing = readers.get(entry.getKey());
             if (existing == null) {
                 readers.put(entry.getKey(), entry.getValue());
             } else {
-                readers.put(entry.getKey(), new CompositeReader(existing, 
entry.getValue()));
+                readers.put(entry.getKey(), new 
CompositeReader(entry.getValue(), existing));
             }
         }
+
         return readers;
     }
 
+    private Method getMethod(final String methodName, final Class<?> type, 
final Class<?>... args) {
+        try {
+            return type.getMethod(methodName, args);
+        } catch (final NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    private Field getField(final String fieldName, final Class<?> type) {
+        Class<?> t = type;
+        while (t != Object.class && t != null) {
+            try {
+                return t.getDeclaredField(fieldName);
+            } catch (final NoSuchFieldException e) {
+                // no-op
+            }
+            t = t.getSuperclass();
+        }
+        return null;
+    }
+
     @Override
     public Map<String, Writer> doFindWriters(final Class<?> clazz) {
-        final Map<String, Writer> writers = new HashMap<String, 
Writer>(fields.findWriters(clazz));
-        for (final Map.Entry<String, Writer> entry : 
methods.findWriters(clazz).entrySet()) {
+        final Map<String, Writer> fieldWriters = 
this.fields.findWriters(clazz);
+        final Map<String, Writer> metodWriters = 
this.methods.findWriters(clazz);
+
+        final Map<String, Writer> writers = new HashMap<String, Writer>();
+
+        for (final Map.Entry<String, Writer> entry : fieldWriters.entrySet()) {
+            final String key = entry.getKey();
+            final Method m = getMethod("set" + 
Character.toUpperCase(key.charAt(0)) + (key.length() > 1 ? key.substring(1) : 
""), clazz, toType(entry.getValue().getType()));
+            boolean skip = false;
+            if (m != null) {
+                for (final Writer w : metodWriters.values()) {
+                    if 
(MethodAccessMode.MethodDecoratedType.class.cast(w).getMethod().equals(m)) {
+                        if (w.getAnnotation(JohnzonProperty.class) != null) {
+                            skip = true;
+                        }
+                        break;
+                    }
+                }
+            }
+            if (skip) {
+                continue;
+            }
+            writers.put(entry.getKey(), entry.getValue());
+        }
+
+        for (final Map.Entry<String, Writer> entry : metodWriters.entrySet()) {
+            final Method mr = 
MethodAccessMode.MethodDecoratedType.class.cast(entry.getValue()).getMethod();
+            final String fieldName = 
Introspector.decapitalize(mr.getName().startsWith("is") ? 
mr.getName().substring(2) : mr.getName().substring(3));
+            final Field f = getField(fieldName, clazz);
+            boolean skip = false;
+            if (f != null) {
+                for (final Writer w : fieldWriters.values()) {
+                    if 
(FieldAccessMode.FieldDecoratedType.class.cast(w).getField().equals(f)) {
+                        if (w.getAnnotation(JohnzonProperty.class) != null) {
+                            skip = true;
+                        }
+                        break;
+                    }
+                }
+            }
+            if (skip) {
+                continue;
+            }
+
             final Writer existing = writers.get(entry.getKey());
             if (existing == null) {
                 writers.put(entry.getKey(), entry.getValue());
             } else {
-                writers.put(entry.getKey(), new CompositeWriter(existing, 
entry.getValue()));
+                writers.put(entry.getKey(), new 
CompositeWriter(entry.getValue(), existing));
             }
         }
         return writers;
     }
 
+    private Class<?> toType(final Type type) {
+        return Class.class.isInstance(type) ? Class.class.cast(type) :
+                (ParameterizedType.class.isInstance(type) ? 
toType(ParameterizedType.class.cast(type).getRawType()) :
+                Object.class /*fallback*/);
+    }
+
     public static abstract class CompositeDecoratedType implements 
DecoratedType {
         protected final DecoratedType type1;
         private final DecoratedType type2;

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index 302b4f4..c81c070 100644
--- 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -52,7 +52,7 @@ public class MethodAccessMode extends BaseAccessMode {
                 if (isIgnored(descriptor.getName()) || 
Meta.getAnnotation(readMethod, JohnzonAny.class) != null) {
                     continue;
                 }
-                readers.put(extractKey(descriptor), new 
MethodReader(readMethod, fixType(clazz, readMethod.getGenericReturnType())));
+                readers.put(extractKey(descriptor.getName(), readMethod, 
null), new MethodReader(readMethod, fixType(clazz, 
readMethod.getGenericReturnType())));
             }
         }
         return readers;
@@ -68,20 +68,24 @@ public class MethodAccessMode extends BaseAccessMode {
             }
             final Method writeMethod = descriptor.getWriteMethod();
             if (writeMethod != null) {
-                writers.put(extractKey(descriptor), new 
MethodWriter(writeMethod, fixType(clazz, 
writeMethod.getGenericParameterTypes()[0])));
+                writers.put(extractKey(descriptor.getName(), writeMethod, 
descriptor.getReadMethod()),
+                        new MethodWriter(writeMethod, fixType(clazz, 
writeMethod.getGenericParameterTypes()[0])));
             } else if (supportGetterAsWritter
                     && 
Collection.class.isAssignableFrom(descriptor.getPropertyType())
                     && descriptor.getReadMethod() != null) {
                 final Method readMethod = descriptor.getReadMethod();
-                writers.put(extractKey(descriptor), new 
MethodGetterAsWriter(readMethod, fixType(clazz, 
readMethod.getGenericReturnType())));
+                writers.put(extractKey(descriptor.getName(), readMethod, 
null), new MethodGetterAsWriter(readMethod, fixType(clazz, 
readMethod.getGenericReturnType())));
             }
         }
         return writers;
     }
 
-    private String extractKey(final PropertyDescriptor f) {
-        final JohnzonProperty property = f.getReadMethod() == null ? null : 
Meta.getAnnotation(f.getReadMethod(), JohnzonProperty.class);
-        return property != null ? property.value() : f.getName();
+    private String extractKey(final String name, final Method from, final 
Method or) {
+        JohnzonProperty property = Meta.getAnnotation(from, 
JohnzonProperty.class);
+        if (property == null && or != null) {
+            property = Meta.getAnnotation(or, JohnzonProperty.class);
+        }
+        return property != null ? property.value() : name;
     }
 
     protected boolean isIgnored(final String name) {

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GetterSetterRespectTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GetterSetterRespectTest.java
 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GetterSetterRespectTest.java
new file mode 100644
index 0000000..a129e11
--- /dev/null
+++ 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GetterSetterRespectTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.mapper;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class GetterSetterRespectTest {
+    @Test
+    public void run() {
+        final Mapper mapper = new MapperBuilder().build();
+        assertEquals("ok", 
Mapped.class.cast(mapper.readObject("{\"name_\":\"ok\"}", Mapped.class)).name);
+
+        final Mapped mapped = new Mapped();
+        mapped.name = "ok";
+        assertEquals("{\"_name\":\"ok\"}", mapper.writeObjectAsString(mapped));
+    }
+
+    public static class Mapped {
+        private String name;
+
+        @JohnzonProperty("_name")
+        public String getName() {
+            return name;
+        }
+
+        @JohnzonProperty("name_")
+        public void setName(final String name) {
+            this.name = name;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonAnyMappingTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonAnyMappingTest.java
 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonAnyMappingTest.java
index cb52d74..6ec0daf 100644
--- 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonAnyMappingTest.java
+++ 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonAnyMappingTest.java
@@ -58,6 +58,8 @@ public class JohnzonAnyMappingTest {
 
     public static class AnyMe {
         private String name;
+
+        @JohnzonIgnore
         private Map<String, Object> any = new TreeMap<String, Object>();
 
         public String getName() {

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-websocket/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-websocket/pom.xml b/johnzon-websocket/pom.xml
index b319669..661ab59 100644
--- a/johnzon-websocket/pom.xml
+++ b/johnzon-websocket/pom.xml
@@ -29,8 +29,8 @@
   <name>Johnzon :: WebSocket</name>
 
   <properties>
-    <tomcat.version>7.0.59</tomcat.version>
-    <tomee.version>1.7.4</tomee.version>
+    <tomcat.version>8.5.3</tomcat.version>
+    <tomee.version>7.0.1</tomee.version>
     
<staging.directory>${project.parent.reporting.outputDirectory}</staging.directory>
   </properties>
 
@@ -61,7 +61,7 @@
       <scope>test</scope>
     </dependency>
      <dependency>
-      <groupId>org.apache.openejb</groupId>
+      <groupId>org.apache.tomee</groupId>
       <artifactId>arquillian-tomee-remote</artifactId>
       <version>${tomee.version}</version>
       <scope>test</scope>
@@ -87,16 +87,22 @@
       </exclusions>
      </dependency> 
     <dependency>
-      <groupId>org.apache.openejb</groupId>
+      <groupId>org.apache.tomee</groupId>
       <artifactId>apache-tomee</artifactId>
       <version>${tomee.version}</version>
       <type>zip</type>
-      <classifier>jaxrs</classifier>
+      <classifier>webprofile</classifier>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat7-websocket</artifactId>
+      <artifactId>tomcat-websocket</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-api</artifactId>
       <version>${tomcat.version}</version>
       <scope>test</scope>
     </dependency>

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/johnzon-websocket/src/test/resources/arquillian.xml
----------------------------------------------------------------------
diff --git a/johnzon-websocket/src/test/resources/arquillian.xml 
b/johnzon-websocket/src/test/resources/arquillian.xml
index c86d7a3..1f2d9d0 100644
--- a/johnzon-websocket/src/test/resources/arquillian.xml
+++ b/johnzon-websocket/src/test/resources/arquillian.xml
@@ -24,7 +24,6 @@
               http://jboss.org/schema/arquillian/arquillian_1_0.xsd";>
   <container qualifier="tomee" default="true">
     <configuration>
-      <property name="classifier">jaxrs</property>
       <property name="httpsPort">-1</property>
       <property name="httpPort">-1</property>
       <property name="stopPort">-1</property>

http://git-wip-us.apache.org/repos/asf/johnzon/blob/b3e496ef/src/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 8c97a99..87fe66b 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -189,6 +189,7 @@ If you don't fully know you model but want to handle all 
keys you can use @Johnz
 
 <pre class="prettyprint linenums"><![CDATA[
 public class AnyMe {
+    @JohnzonAny // ignore normal serialization of this field
     private String name; // known
     private Map<String, Object> any = new TreeMap<String, Object>(); // unknown
 
@@ -221,6 +222,7 @@ The default available names are:
 * field: to use fields model and ignore getters/setters
 * method: use getters/setters (means if you have a getter but no setter you 
will serialize the property but not read it)
 * strict-method (default based on Pojo convention): same as method but getters 
for collections are not used to write
+* both: field and method accessors are merged together
 
 You can use these names with setAccessModeName().
 

Reply via email to