In a prior post, I used Commons Configuration to detect duplicate properties in a Properties file. The code was very simple.
Here I present a solution using a Dynamic Proxy class. A complexity is that though Properties extends the Map interface, that interface does not declare a load method. And, the JDK Dynamic Proxy support can only be used for interfaces, not concrete classes. The Javassist library can be used for this purpose as shown in listing 1 below.
Listing 1, dupe detect with Javassist Source Gist
package com.octodecillion.util; import java.io.IOException; import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javassist.util.proxy.MethodFilter; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; /** * Detect duplicate properties when loading Properties from stream. * <p> * This version uses <a href="https://jboss-javassist.github.io/javassist/">Javassist</a> Dynamic Proxy support. * * @author jbetancourt * @since Nov 18, 2015 */ public class DuplicatePropertyDetectorWithJavassist { /** * Detect duplicate keys in Properties resource. * <p> * @see Properties#load(Reader) * * @param reader The reader is <b>NOT</b> closed. * @return Map Map where map key is duplicated key and list is values of those keys * @throws IOException reading the stream * @throws RuntimeException for any issue with proxying */ public Map<String, List<String>> load(Reader reader) throws IOException { if(reader==null){ throw new NullPointerException("reader cannot be null");} final Map<String, List<String>> dupeResults = new HashMap<>(); final String put_method_name = "put"; try { ProxyFactory factory = new ProxyFactory(); factory.setSuperclass(Properties.class); factory.setFilter(new MethodFilter() { @Override public boolean isHandled(Method m) { return m.getName().equals(put_method_name); } }); ((Properties) factory.create(new Class<?>[0], new Object[0], new MethodHandler() { @Override public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { String key = (String) args[0],value = (String) args[1]; if (((Properties) self).containsKey(key)) { List<String> list = new ArrayList<>(); if (dupeResults.containsKey(key)) { list = dupeResults.get(key); } else { dupeResults.put(key, list); } list.add(value); } return proceed.invoke(self, args); } })).load(reader); } catch (NoSuchMethodException | IllegalArgumentException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } return dupeResults; } }
Links
Javassist
One thought on “Java Properties dupe key detect using Javassist”