--- /dev/null 2013-09-26 12:31:35.724641065 +0400 +++ new/src/share/demo/extension-methods/MixIn.java 2013-09-27 18:41:00.438187662 +0400 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + */ + + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * The example illustrates how we can use default method for mix in + * + * @see MixClass + * @see Debuggable + * @see Equalable + * @see Hashable + */ +public class MixIn { + + /** + * Implement this interface for class that needs in debug print + */ + public interface Debuggable { + + /** + * Print the class name and all data members to string. Reflection is + * used for it. + * + * @return the string formatted like below:
+         * State of the: <Class Name>
+         * <member name> : <value>
+         * ...
+         * 
+ */ + default String toDebugString() { + StringBuilder sb = new StringBuilder(); + sb.append("State of the: ").append(this.getClass().getSimpleName()).append("\n"); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + try { + f.setAccessible(true); + sb.append(f.getName()).append(" : ").append(f.get(this)).append("\n"); + } catch (IllegalAccessException e) { + } + } + } + return sb.toString(); + } + } + + public interface Equalable { + + /** + * Indicates whether some other object is "equal to" this one. Uses + * reflection to access to data members. Two objects equal if all them + * members (except members from #excludeFields list) are equal. + * + * @param obj object to compare + * @param excludeFields the values of these fields don't affect to the + * return value + * @return {@code true} if this object is the same as the obj argument; + * {@code false} otherwise. + */ + default boolean equalsReflect(Object obj, String... excludeFields) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Set excludes = new HashSet<>(Arrays.asList(excludeFields)); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + if (excludes.contains(f.getName())) { + break; + } + try { + f.setAccessible(true); + Object thisFieldVal = f.get(this); + Object oFieldVal = f.get(obj); + if (thisFieldVal != null) { + if (!thisFieldVal.equals(oFieldVal)) { + return false; + } + } else if (oFieldVal != null) { + return false; + } + } catch (IllegalAccessException e) { + } + } + } + return true; + } + } + + public interface Hashable { + + /** + * Returns a hash code value for the object. This method uses reflection + * to access to object's data members. Hash code is calculated on + * members hash codes. + * + * @param excludeFields the values of these fields don't affect to the + * return value + * + * @return a hash code value for this object. + */ + default int hashCodeReflect(String... excludeFields) { + int result = 0; + Set excludes = new HashSet<>(Arrays.asList(excludeFields)); + for (Class cls = this.getClass(); cls != null; cls = cls.getSuperclass()) { + for (Field f : cls.getDeclaredFields()) { + if (excludes.contains(f.getName())) { + break; + } + try { + f.setAccessible(true); + Object val = f.get(this); + result = 31 * result + val.hashCode(); + } catch (IllegalAccessException e) { + } + } + } + return result; + } + } + + /** + * Sample class to demonstrate mixin. This class inherit behavior of the + * {@link Debuggable}, {@link Equalable}, {@link Hashable} + */ + public static class MixClass implements Debuggable, Equalable, Hashable { + + private final int n = 28; + private final String strHello = "Hello world"; + + /** + * Use default method from {@link Equalable} to check equals + */ + @Override + public boolean equals(Object o) { + return equalsReflect(o); + } + + /** + * Use default method from {@link Hashable} to calculate hash code + */ + @Override + public int hashCode() { + return hashCodeReflect(); + } + } + + public static void main(String args[]) throws IOException { + MixClass a = new MixClass(); + MixClass b = new MixClass(); + System.out.println(a.toDebugString()); + System.out.println(a.equals(b)); + } +}