org.joda.beans.impl.direct.MinimalMetaBean Maven / Gradle / Ivy
/*
* Copyright 2001-present Stephen Colebourne
*
* 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 org.joda.beans.impl.direct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.MetaProperty;
import org.joda.beans.TypedMetaBean;
import org.joda.beans.gen.DerivedProperty;
import org.joda.beans.gen.PropertyDefinition;
/**
* A meta-bean implementation designed for use by the code generator.
*
* @author Stephen Colebourne
* @param the type of the bean
*/
public final class MinimalMetaBean implements TypedMetaBean {
/** The bean type. */
private final Class beanType;
/** The constructor to use. */
private final Supplier> builderSupplier;
/** The meta-property instances of the bean. */
private final Map> metaPropertyMap;
/** The aliases. */
private final Map aliasMap;
/**
* Obtains an instance of the meta-bean for immutable beans.
*
* The properties will be determined using reflection to find the
* {@link PropertyDefinition} annotation.
*
* @param the type of the bean
* @param beanType the bean type, not null
* @param builderSupplier the supplier of bean builders, not null
* @param getters the getter functions, not null
* @return the meta-bean, not null
* @deprecated Use version that takes the field names
*/
@Deprecated
@SafeVarargs
public static MinimalMetaBean of(
Class beanType,
Supplier> builderSupplier,
Function... getters) {
if (getters == null) {
throw new NullPointerException("Getter functions must not be null");
}
return new MinimalMetaBean<>(beanType, fieldNames(beanType), builderSupplier, Arrays.asList(getters), null);
}
/**
* Obtains an instance of the meta-bean for immutable beans.
*
* The properties will be determined using reflection to find the
* {@link PropertyDefinition} annotation.
* The field names must be specified as reflection does not return fields in source code order.
*
* @param the type of the bean
* @param beanType the bean type, not null
* @param fieldNames the field names, not null
* @param builderSupplier the supplier of bean builders, not null
* @param getters the getter functions, not null
* @return the meta-bean, not null
*/
@SafeVarargs
public static MinimalMetaBean of(
Class beanType,
String[] fieldNames,
Supplier> builderSupplier,
Function... getters) {
if (getters == null) {
throw new NullPointerException("Getter functions must not be null");
}
return new MinimalMetaBean<>(beanType, fieldNames, builderSupplier, Arrays.asList(getters), null);
}
/**
* Obtains an instance of the meta-bean for mutable beans.
*
* The properties will be determined using reflection to find the
* {@link PropertyDefinition} annotation.
*
* @param the type of the bean
* @param beanType the bean type, not null
* @param builderSupplier the supplier of bean builders, not null
* @param getters the getter functions, not null
* @param setters the setter functions, not null
* @return the meta-bean, not null
* @deprecated Use version that takes the field names
*/
@Deprecated
public static MinimalMetaBean of(
Class beanType,
Supplier> builderSupplier,
List> getters,
List> setters) {
if (getters == null) {
throw new NullPointerException("Getter functions must not be null");
}
if (setters == null) {
throw new NullPointerException("Setter functions must not be null");
}
return new MinimalMetaBean<>(beanType, fieldNames(beanType), builderSupplier, getters, setters);
}
/**
* Obtains an instance of the meta-bean for mutable beans.
*
* The properties will be determined using reflection to find the
* {@link PropertyDefinition} annotation.
* The field names must be specified as reflection does not return fields in source code order.
*
* @param the type of the bean
* @param beanType the bean type, not null
* @param fieldNames the field names, not null
* @param builderSupplier the supplier of bean builders, not null
* @param getters the getter functions, not null
* @param setters the setter functions, not null
* @return the meta-bean, not null
*/
public static MinimalMetaBean of(
Class beanType,
String[] fieldNames,
Supplier> builderSupplier,
List> getters,
List> setters) {
if (getters == null) {
throw new NullPointerException("Getter functions must not be null");
}
if (setters == null) {
throw new NullPointerException("Setter functions must not be null");
}
return new MinimalMetaBean<>(beanType, fieldNames, builderSupplier, getters, setters);
}
/**
* Constructor.
*
* @param beanType the bean type, not null
* @param builderSupplier the supplier of bean builders, not null
* @param fieldNames the field names, not null
* @param getters the getter functions, not null
* @param setters the setter functions, may be null
*/
private MinimalMetaBean(
Class beanType,
String[] fieldNames,
Supplier> builderSupplier,
List> getters,
List> setters) {
if (beanType == null) {
throw new NullPointerException("Bean class must not be null");
}
if (builderSupplier == null) {
throw new NullPointerException("Supplier of BeanBuilder must not be null");
}
if (fieldNames == null) {
throw new NullPointerException("Field names must not be null");
}
if (fieldNames.length != getters.size()) {
throw new IllegalArgumentException("Number of getter functions must match number of fields");
}
if (setters != null && fieldNames.length != setters.size()) {
throw new IllegalArgumentException("Number of setter functions must match number of fields");
}
this.beanType = beanType;
this.builderSupplier = builderSupplier;
// extract fields and match to getters/setters
Map> map = new LinkedHashMap<>();
for (int i = 0; i < fieldNames.length; i++) {
String fieldName = fieldNames[i];
Field field;
try {
field = beanType.getDeclaredField(fieldName);
} catch (NoSuchFieldException ex) {
throw new IllegalArgumentException(ex);
}
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException("Field must not be static");
}
if (field.getAnnotation(PropertyDefinition.class) == null) {
throw new IllegalArgumentException("Field must have PropertyDefinition annotation");
}
map.put(fieldName, new MinimalMetaProperty<>(
this, fieldName, field, getters.get(i), setters != null ? setters.get(i) : null));
}
// derived
Method[] methods = beanType.getDeclaredMethods();
for (Method method : methods) {
if (!Modifier.isStatic(method.getModifiers()) &&
Modifier.isPublic(method.getModifiers()) &&
method.getAnnotation(DerivedProperty.class) != null &&
method.getName().startsWith("get") &&
method.getName().length() > 3 &&
Character.isUpperCase(method.getName().charAt(3)) &&
method.getParameterTypes().length == 0) {
String methodName = method.getName();
String propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
MetaProperty