org.openrdf.repository.object.managers.PropertyMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alibaba-composition-object Show documentation
Show all versions of alibaba-composition-object Show documentation
The Object Composition library merges multiple Java objects into a single multi-subject object.
/*
* Copyright (c) 2009, James Leigh All rights reserved.
* Copyright (c) 2011 Talis Inc., Some rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.openrdf.repository.object.managers;
import static java.util.Locale.ENGLISH;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.openrdf.annotations.Iri;
import org.openrdf.model.vocabulary.RDF;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Reads in property mapping files and determines which properties should be
* eagarly loaded.
*
* @author James Leigh
*
*/
public class PropertyMapper {
private static final String PROPERTIES = "META-INF/org.openrdf.properties";
private static final String GET_PREFIX = "get";
private static final String SET_PREFIX = "set";
private static final String IS_PREFIX = "is";
private Logger logger = LoggerFactory
.getLogger(PropertyMapper.class);
private boolean readTypes;
private Properties properties = new Properties();
public PropertyMapper(ClassLoader cl, boolean readTypes) {
loadProperties(cl);
this.readTypes = readTypes;
}
public boolean isReadingTypes() {
return readTypes;
}
public Collection findFields(Class> concept) {
List fields = new ArrayList();
for (Field field : concept.getDeclaredFields()) {
if (isMappedField(field)) {
fields.add(field);
}
}
return fields;
}
public Collection findProperties(Class> concept) {
List properties = new ArrayList();
for (Method method : concept.getDeclaredMethods()) {
if (isMappedGetter(method)) {
properties.add(createPropertyDescriptor(method));
}
}
return properties;
}
public String findPredicate(Field field) {
Class> dc = field.getDeclaringClass();
String key = dc.getName() + "#" + field.getName();
if (properties.containsKey(key))
return (String) properties.get(key);
Iri rdf = field.getAnnotation(Iri.class);
if (rdf == null)
return null;
return rdf.value();
}
public String findPredicate(PropertyDescriptor pd) {
Method method = pd.getReadMethod();
Class> dc = method.getDeclaringClass();
String key = dc.getName() + "." + getPropertyName(method);
if (properties.containsKey(key))
return (String) properties.get(key);
Method getter = method;
Iri rdf = getter.getAnnotation(Iri.class);
if (rdf == null)
return null;
return rdf.value();
}
public Collection findFunctionalProperties(Class> type) {
Map properties = new HashMap();
findFunctionalProperties(type, properties);
return properties.values();
}
public Collection findFunctionalFields(Class> type) {
if (type.isInterface())
return Collections.emptySet();
Map properties = new HashMap();
findFunctionalFields(type, properties);
return properties.values();
}
/** @return map of name to uri */
public Map findEagerProperties(Class> type) {
Map properties = new HashMap();
findEagerProperties(type, properties);
if (properties.isEmpty())
return null;
if (readTypes) {
properties.put("class", RDF.TYPE.stringValue());
}
return properties;
}
public boolean isMappedField(Field field) {
if (field.isAnnotationPresent(Iri.class))
return true;
if (properties.isEmpty())
return false;
String name = field.getDeclaringClass().getName();
String key = name + "#" + field.getName();
return properties.containsKey(key);
}
private void findFunctionalProperties(Class> concept,
Map properties) {
for (PropertyDescriptor pd : findProperties(concept)) {
Class> type = pd.getPropertyType();
if (Set.class.equals(type))
continue;
properties.put(pd.getName(), pd);
}
for (Class> face : concept.getInterfaces()) {
findFunctionalProperties(face, properties);
}
if (concept.getSuperclass() != null)
findFunctionalProperties(concept.getSuperclass(), properties);
}
private void findFunctionalFields(Class> concept,
Map properties) {
for (Field field : findFields(concept)) {
Class> type = field.getType();
if (Set.class.equals(type))
continue;
properties.put(field.getName(), field);
}
if (concept.getSuperclass() != null)
findFunctionalFields(concept.getSuperclass(), properties);
}
private Map findEagerProperties(Class> concept,
Map properties) {
for (PropertyDescriptor pd : findProperties(concept)) {
Class> type = pd.getPropertyType();
Type generic = pd.getReadMethod().getGenericReturnType();
if (!isEagerPropertyType(generic, type))
continue;
properties.put(pd.getName(), findPredicate(pd));
}
for (Field field : findFields(concept)) {
Class> type = field.getType();
if (!isEagerPropertyType(field.getGenericType(), type))
continue;
properties.put(field.getName(), findPredicate(field));
}
for (Class> face : concept.getInterfaces()) {
findEagerProperties(face, properties);
}
if (concept.getSuperclass() == null)
return properties;
return findEagerProperties(concept.getSuperclass(), properties);
}
private boolean isEagerPropertyType(Type t, Class> type) {
if (Set.class.equals(type))
return false;
if (!readTypes)
return true;
if (type.isInterface())
return false;
if (Object.class.equals(type))
return false;
if (type.isAnnotationPresent(Iri.class))
return false;
return true;
}
private void loadProperties(ClassLoader cl) {
try {
Enumeration resources = cl.getResources(PROPERTIES);
while (resources.hasMoreElements()) {
try {
InputStream stream = resources.nextElement().openStream();
try {
properties.load(stream);
} finally {
stream.close();
}
} catch (IOException e) {
logger.warn(e.toString(), e);
}
}
} catch (IOException e) {
logger.warn(e.toString(), e);
}
}
private boolean isMappedGetter(Method method) {
if (method.getParameterTypes().length != 0)
return false;
if (getPropertyName(method) == null)
return false;
if (method.isAnnotationPresent(Iri.class))
return true;
if (properties.isEmpty())
return false;
String name = method.getDeclaringClass().getName();
String key = name + "." + getPropertyName(method);
return properties.containsKey(key);
}
private PropertyDescriptor createPropertyDescriptor(Method method) {
String property = getPropertyName(method);
Method setter = getSetterMethod(property, method);
try {
return new PropertyDescriptor(property, method, setter);
} catch (IntrospectionException e) {
// property name is bad
throw new AssertionError(e);
}
}
private String getPropertyName(Method method) {
String name = method.getName();
boolean bool = method.getReturnType() == boolean.class;
if (name.startsWith(GET_PREFIX) && name.length() > 3) {
// Simple getter
return decapitalize(name.substring(3));
} else if (bool && name.startsWith(IS_PREFIX) && name.length() > 2) {
// Boolean getter
return decapitalize(name.substring(2));
}
return null;
}
private static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1))
&& Character.isUpperCase(name.charAt(0))) {
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
private Method getSetterMethod(String property, Method getter) {
try {
Class> dc = getter.getDeclaringClass();
Class> rt = getter.getReturnType();
String setter = SET_PREFIX + capitalize(property);
return dc.getDeclaredMethod(setter, rt);
} catch (NoSuchMethodException exc) {
return null;
}
}
private static String capitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
}
}