/*
 * Copyright 2017 Crown Copyright
 *
 * Licensed 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 stroom.config.global.impl.db;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public final class BeanUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(BeanUtil.class);

    private BeanUtil() {
        // Utility class.
    }

    public static Map<String, Prop> getProperties(final Object object) {
        final Class<?> clazz = object.getClass();
        final Method[] methods = clazz.getDeclaredMethods();
        final Map<String, Prop> propMap = new HashMap<>();
        for (final Method method : methods) {
            final String methodName = method.getName();

            if (methodName.startsWith("is")) {
                // Boolean Getter.

                if (methodName.length() > 2 && method.getParameterTypes().length == 0 && !method.getReturnType().equals(Void.TYPE)) {
                    final String name = getPropertyName(methodName, 2);
                    final Prop prop = propMap.computeIfAbsent(name, k -> new Prop(name, object));
                    prop.getter = method;
                }

            } else if (methodName.startsWith("get")) {
                // Getter.

                if (methodName.length() > 3 && !methodName.equals("getClass") && method.getParameterTypes().length == 0 && !method.getReturnType().equals(Void.TYPE)) {
                    final String name = getPropertyName(methodName, 3);
                    final Prop prop = propMap.computeIfAbsent(name, k -> new Prop(name, object));
                    prop.getter = method;
                }
            } else if (methodName.startsWith("set")) {
                // Setter.

                if (methodName.length() > 3 && method.getParameterTypes().length == 1 && method.getReturnType().equals(Void.TYPE)) {
                    final String name = getPropertyName(methodName, 3);
                    final Prop prop = propMap.computeIfAbsent(name, k -> new Prop(name, object));
                    prop.setter = method;
                }
            }
        }

        return propMap
                .entrySet()
                .stream()
                .filter(e -> {
                    if (e.getValue().getter == null || e.getValue().setter == null) {
                        LOGGER.debug("Invalid property " + e.getKey() + " on " + clazz.getName());
                        return false;
                    }
                    return true;
                })
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    }

    private static String getPropertyName(final String methodName, final int len) {
        final String name = methodName.substring(len);
        return name.substring(0, 1).toLowerCase() + name.substring(1);
    }

    public static class Prop {
        private final String name;
        private final Object object;
        private Method getter;
        private Method setter;

        Prop(final String name, final Object object) {
            this.name = name;
            this.object = object;
        }

        public String getName() {
            return name;
        }

        public Object getObject() {
            return object;
        }

        public Method getGetter() {
            return getter;
        }

        public Method getSetter() {
            return setter;
        }
    }
}

@@ -636,16 +636,68 @@
 l.db;%0A%0A%0A
+import com.fasterxml.jackson.annotation.JsonIgnore;%0A
 import o
@@ -1405,24 +1405,102 @@
 getName();%0A%0A
+            if (method.getDeclaredAnnotation(JsonIgnore.class) == null) %7B%0A    
             
@@ -1550,16 +1550,20 @@
         
+    
 // Boole
@@ -1566,32 +1566,36 @@
 oolean Getter.%0A%0A
+    
                 
@@ -1724,32 +1724,36 @@
                 
+  
+  
 final String nam
@@ -1788,16 +1788,20 @@
 me, 2);%0A
+    
         
@@ -1902,32 +1902,36 @@
                 
+    
 prop.getter = me
@@ -1944,35 +1944,43 @@
                 
+ 
-%7D%0A%0A
+   %7D%0A%0A    
             %7D el
@@ -2010,32 +2010,36 @@
 sWith(%22get%22)) %7B%0A
+    
                 
@@ -2058,32 +2058,36 @@
                 
+    
 if (methodName.l
@@ -2234,32 +2234,36 @@
                 
+    
 final String nam
@@ -2310,32 +2310,36 @@
                 
+   
+ 
 final Prop prop 
@@ -2412,32 +2412,36 @@
                 
+    
 prop.getter = me
@@ -2454,34 +2454,40 @@
                 
-%7D%0A
+    %7D%0A  
             %7D el
@@ -2474,32 +2474,34 @@
 %7D%0A              
+  
 %7D else if (metho
@@ -2543,16 +2543,20 @@
         
+    
 // Sette
@@ -2551,32 +2551,36 @@
     // Setter.%0A%0A
+    
                 
@@ -2708,32 +2708,36 @@
                 
+ 
+   
 final String nam
@@ -2764,32 +2764,36 @@
 methodName, 3);%0A
+    
                 
@@ -2866,32 +2866,36 @@
 name, object));%0A
+    
                 
@@ -2912,32 +2912,54 @@
 etter = method;%0A
+                    %7D%0A
                 

Change BeanUtil to ignore @JsonIgnore methods