grails.beans.util.LazyMetaPropertyMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of grails-core Show documentation
Show all versions of grails-core Show documentation
Grails Web Application Framework
/*
* Copyright 2004-2005 the original author or authors.
*
* 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 grails.beans.util;
import groovy.lang.GroovySystem;
import groovy.lang.MetaBeanProperty;
import groovy.lang.MetaClass;
import groovy.lang.MetaProperty;
import groovy.transform.CompileStatic;
import groovy.util.MapEntry;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import grails.core.GrailsDomainClassProperty;
import org.grails.core.support.GrailsDomainConfigurationUtil;
import org.springframework.util.Assert;
/**
* A map implementation that reads an objects properties lazily using Groovy's MetaClass.
*
* @author Graeme Rocher
*/
@SuppressWarnings({"unchecked","rawtypes"})
@CompileStatic
public class LazyMetaPropertyMap implements Map {
private MetaClass metaClass;
private Object instance;
private static List EXCLUDES = Arrays.asList("properties", GrailsDomainClassProperty.IDENTITY, GrailsDomainClassProperty.VERSION, "domainClass", "dirty", GrailsDomainClassProperty.ERRORS, "dirtyPropertyNames");
/**
* Constructs the map
* @param o The object to inspect
*/
public LazyMetaPropertyMap(Object o) {
Assert.notNull(o, "Object cannot be null");
instance = o;
metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(o.getClass());
}
/**
* {@inheritDoc}
* @see java.util.Map#size()
*/
public int size() {
return keySet().size();
}
/**
* {@inheritDoc}
* @see java.util.Map#isEmpty()
*/
public boolean isEmpty() {
return false; // will never be empty
}
/**
* {@inheritDoc}
* @see java.util.Map#containsKey(java.lang.Object)
*/
public boolean containsKey(Object propertyName) {
if (propertyName instanceof CharSequence) propertyName = propertyName.toString();
Assert.isInstanceOf(String.class, propertyName, "This map implementation only supports String based keys!");
String pn = propertyName.toString();
return !GrailsDomainConfigurationUtil.isConfigurational(pn) && metaClass.getMetaProperty(pn) != null;
}
/**
* Checks whether the specified value is contained within the Map. Note that because this implementation
* lazily initialises property values the behaviour may not be consistent with the actual values of the
* contained object unless they have already been initialised by calling get(Object)
*
* @see java.util.Map#containsValue(Object)
*/
public boolean containsValue(Object o) {
return values().contains(o);
}
/**
* Obtains the value of an object's properties on demand using Groovy's MOP.
*
* @param propertyName The name of the property
* @return The property value or null
*/
public Object get(Object propertyName) {
if (propertyName instanceof CharSequence) {
propertyName = propertyName.toString();
}
if (propertyName instanceof List) {
Map submap = new HashMap();
List propertyNames = (List)propertyName;
for (Object currentName : propertyNames) {
if (currentName != null) {
currentName = currentName.toString();
if (containsKey(currentName)) {
submap.put(currentName, get(currentName));
}
}
}
return submap;
}
if (GrailsDomainConfigurationUtil.isConfigurational(propertyName.toString())) {
return null;
}
Object val = null;
MetaProperty mp = metaClass.getMetaProperty(propertyName.toString());
if (mp != null) {
val = mp.getProperty(instance);
}
return val;
}
public Object put(Object propertyName, Object propertyValue) {
if (propertyName instanceof CharSequence) {
propertyName = propertyName.toString();
}
Object old = null;
MetaProperty mp = metaClass.getMetaProperty((String)propertyName);
if (mp != null && !isExcluded(mp)) {
old = mp.getProperty(instance);
if (propertyValue instanceof Map) {
propertyValue = ((Map)propertyValue).get(propertyName);
}
mp.setProperty(instance, propertyValue);
}
return old;
}
/**
* @throws UnsupportedOperationException
*/
public Object remove(Object o) {
throw new UnsupportedOperationException("Method remove(Object o) is not supported by this implementation");
}
public void putAll(Map map) {
for (Iterator i = map.keySet().iterator(); i.hasNext();) {
Object key = i.next();
put(key, map.get(key));
}
}
/**
* @throws UnsupportedOperationException
*/
public void clear() {
throw new UnsupportedOperationException("Method clear() is not supported by this implementation");
}
public Set keySet() {
Set names = new HashSet();
for (MetaProperty mp : metaClass.getProperties()) {
if (isExcluded(mp)) continue;
names.add(mp.getName());
}
return names;
}
public Collection