package net.karneim.pojobuilder.model; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import net.karneim.pojobuilder.analysis.PropertyPattern; import net.karneim.pojobuilder.model.WriteAccess.Type; public class PropertyListM implements Iterable<PropertyM> { private LinkedHashMap<Key, PropertyM> elements = new LinkedHashMap<Key, PropertyM>(); public PropertyListM(Iterable<PropertyM> other) { for (PropertyM t : other) { add(t); } } public PropertyListM(PropertyM... elems) { this(Arrays.asList(elems)); } @Override public Iterator<PropertyM> iterator() { return elements.values().iterator(); } public PropertyM get(String propertyName, TypeM propertyType) { return get(new Key(propertyName, propertyType)); } public PropertyM get(Key key) { return elements.get(key); } public PropertyM getOrCreate(String propertyName, TypeM propertyType) { PropertyM elem = elements.get(new Key(propertyName, propertyType)); if (elem == null) { elem = new PropertyM(propertyName, propertyType); add(elem); } return elem; } public PropertyListM add(PropertyM prop) { Key key = keyOf(prop); if (elements.containsKey(key)) { throw new IllegalArgumentException(String.format("Property with key %s already in list!", key)); } elements.put(key, prop); return this; } private Key keyOf(PropertyM prop) { Key result = new Key(prop.getPropertyName(), prop.getPropertyType()); return result; } public PropertyListM filterOutNonWritableProperties(TypeM accessingClass) { PropertyListM result = new PropertyListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.isWritableBy(accessingClass) == false) { result.add(p); it.remove(); } } return result; } public PropertyListM filterOutPropertiesWritableBy(Type type, TypeM accessingClass) { PropertyListM result = new PropertyListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.getPreferredWriteAccessFor(accessingClass).getType() == type) { result.add(p); it.remove(); } } return result; } public ArgumentListM toArgumentList(Type type, TypeM accessingClass) { ArgumentListM result = new ArgumentListM(); for (PropertyM p : this) { WriteAccess writeAccess = p.getPreferredWriteAccessFor(accessingClass); if (writeAccess.getType() == type) { Positional positional = (Positional) writeAccess; int pos = positional.getPos(); result.add(new ArgumentM(p, pos)); } } return result; } public ArgumentListM filterOutPropertiesWritableViaConstructorParameter(TypeM accessingClass) { ArgumentListM result = new ArgumentListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.getPreferredWriteAccessFor(accessingClass).getType() == Type.CONSTRUCTOR) { int pos = p.getConstructorParameter().getPos(); result.add(new ArgumentM(p, pos)); it.remove(); } } return result; } public ArgumentListM filterOutPropertiesWritableViaFactoryMethodParameter(TypeM accessingClass) { ArgumentListM result = new ArgumentListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.getPreferredWriteAccessFor(accessingClass).getType() == Type.FACTORY) { int pos = p.getFactoryMethodParameter().getPos(); result.add(new ArgumentM(p, pos)); it.remove(); } } return result; } public PropertyListM filterOutPropertiesReadableViaGetterCall(TypeM accessingClass) { PropertyListM result = new PropertyListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.isReadableViaGetterMethodBy(accessingClass)) { result.add(p); it.remove(); } } return result; } public PropertyListM filterOutPropertiesReadableViaFieldAccess(TypeM accessingClass) { PropertyListM result = new PropertyListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.isReadableViaFieldAccessBy(accessingClass)) { result.add(p); it.remove(); } } return result; } public PropertyListM filterOutPropertiesReadableBy(TypeM accessingClass) { PropertyListM result = new PropertyListM(); Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.isReadableViaFieldAccessBy(accessingClass) || p.isReadableViaGetterMethodBy(accessingClass)) { result.add(p); it.remove(); } } return result; } public void retainPropertiesMatchingAnyOf(List<PropertyPattern> list) { Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (!p.matchesAnyOf(list)) { // We won't exclude mandatory properties if (!p.isWritableViaConstructor() && !p.isWritableViaFactoryMethod()) { it.remove(); } } } } public void removePropertiesMatchingAnyOf(List<PropertyPattern> list) { if (list.isEmpty()) { return; } Iterator<PropertyM> it = this.iterator(); while (it.hasNext()) { PropertyM p = it.next(); if (p.matchesAnyOf(list)) { // We won't exclude mandatory properties if (!p.isWritableViaConstructor() && !p.isWritableViaFactoryMethod()) { it.remove(); } } } } public boolean hasPropertiesReadablyBy(TypeM accessingClass) { return new PropertyListM(this).filterOutPropertiesReadableBy(accessingClass).isEmpty() == false; } public boolean isEmpty() { return elements.isEmpty(); } public TypeListM getTypes() { TypeListM result = new TypeListM(); for (PropertyM p : this) { result.add(p.getPropertyType()); } return result; } @Override public String toString() { return "PropertyListM [elements=" + elements + "]"; } public static class Key { String propertyName; String propertyType; public Key(String propertyName, TypeM propertyType) { this(propertyName, propertyType.getGenericType()); } public Key(String propertyName, String propertyType) { this.propertyName = propertyName; this.propertyType = propertyType; } @Override public String toString() { return "Key [propertyName=" + propertyName + ", propertyType=" + propertyType + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); result = prime * result + ((propertyType == null) ? 0 : propertyType.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Key other = (Key) obj; if (propertyName == null) { if (other.propertyName != null) return false; } else if (!propertyName.equals(other.propertyName)) return false; if (propertyType == null) { if (other.propertyType != null) return false; } else if (!propertyType.equals(other.propertyType)) return false; return true; } } }