All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.restup.mapping.fields.MappedField Maven / Gradle / Ivy
package com.github.restup.mapping.fields;
import static com.github.restup.util.ReflectionUtils.makeAccessible;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import com.github.restup.annotations.field.CaseInsensitive;
import com.github.restup.annotations.field.Immutable;
import com.github.restup.annotations.field.Param;
import com.github.restup.annotations.field.Relationship;
import com.github.restup.annotations.field.RelationshipType;
import com.github.restup.mapping.fields.composition.CaseSensitivity;
import com.github.restup.mapping.fields.composition.Identifier;
import com.github.restup.mapping.fields.composition.Immutability;
import com.github.restup.mapping.fields.composition.MapField;
import com.github.restup.mapping.fields.composition.ReflectMappedField;
import com.github.restup.mapping.fields.composition.ReflectMappedMethod;
import com.github.restup.mapping.fields.composition.ReflectReadableMappedMethod;
import com.github.restup.mapping.fields.composition.ReflectWritableMappedMethod;
import com.github.restup.mapping.fields.composition.Relation;
import com.github.restup.path.MappedFieldPathValue;
import com.github.restup.registry.Resource;
import com.github.restup.registry.ResourceRegistry;
import com.github.restup.util.Assert;
import com.github.restup.util.ReflectionUtils;
import com.github.restup.util.ReflectionUtils.BeanInfo;
import com.github.restup.util.ReflectionUtils.PropertyDescriptor;
/**
* Captures meta data about fields for mapping api
*/
public interface MappedField extends ReadWriteField {
//TODO doc
/**
*
* @param mappedField providing relationship name
* @param resource providing default name
* @return The relationship name from the mappedField or the resource name by default
*/
static String getRelationshipName(MappedField> mappedField, Resource, ?> resource) {
String name = mappedField.getRelationshipName();
if (StringUtils.isEmpty(name)) {
name = resource.getName();
}
return name;
}
static Object toCaseInsensitive(MappedFieldPathValue> mfpv, Object value) {
return toCaseInsensitive(mfpv.getMappedField().getCaseSensitivity(), value);
}
@SuppressWarnings({"rawtypes", "unchecked"})
static Object toCaseInsensitive(CaseSensitivity caseSensitivity, Object value) {
if (value instanceof Collection) {
Collection result = (Collection) ReflectionUtils.newInstance(value.getClass());
for (Object o : (Collection) value) {
result.add(toCaseInsensitive(caseSensitivity, o));
}
return result;
} else if (value instanceof String) {
String s = (String) value;
return caseSensitivity.isLowerCased() ? s.toLowerCase() : s.toUpperCase();
}
return null;
}
static boolean isCaseInsensitive(MappedField> mf) {
return mf != null && mf.isCaseInsensitive();
}
static MappedField> getIdentityField(List> attributes) {
return attributes.stream()
.filter(MappedField::isIdentifier)
.findFirst()
.get();
}
public static BasicMappedField.Builder builder(Class type) {
return new BasicMappedField.Builder(type);
}
public static BasicMappedField.Builder> builder(Type type) {
return new BasicMappedField.Builder<>(type);
}
Type getType();
T newInstance();
String getBeanName();
String getApiName();
String getPersistedName();
boolean isCollection();
boolean isTransientField();
boolean isApiProperty();
Identifier getIdentifier();
default boolean isIdentifier() {
return getIdentifier() != null;
}
default boolean isIdentifierNonAutoGeneratedValuePermitted() {
return applyToIdentifier(Identifier::isNonAutoGeneratedValuePermitted);
}
/**
* null safe. apply f to {@link #getIdentifier()}
*
* @param result of function
* @param f function to apply
* @return result of function
*/
default R applyToIdentifier(Function f) {
Identifier identifier = getIdentifier();
return identifier == null ? null : f.apply(identifier);
}
CaseSensitivity getCaseSensitivity();
default boolean isCaseInsensitive() {
return applyToCaseSensitivity(CaseSensitivity::isCaseInsensitive) == Boolean.TRUE;
}
default String getCaseInsensitiveSearchField() {
return applyToCaseSensitivity(CaseSensitivity::getSearchField);
}
/**
* null safe. apply f to {@link #getCaseSensitivity()}
*
* @param result of function
* @param f function to apply
* @return result of function
*/
default R applyToCaseSensitivity(Function f) {
CaseSensitivity caseSensitivity = getCaseSensitivity();
return caseSensitivity == null ? null : f.apply(caseSensitivity);
}
Immutability getImmutability();
default boolean isImmutable() {
return applyToImmutability(Immutability::isImmutable) == Boolean.TRUE;
}
default boolean isImmutabilityErrorOnUpdateAttempt() {
return applyToImmutability(Immutability::isErrorOnUpdateAttempt) == Boolean.TRUE;
}
default boolean isImmutabilityIgnoreUpdateAttempt() {
return applyToImmutability(Immutability::isIgnoreUpdateAttempt) == Boolean.TRUE;
}
/**
* null safe. apply f to {@link #getImmutability()}
*
* @param result of function
* @param f function to apply
* @return result of function
*/
default R applyToImmutability(Function f) {
Immutability immutability = getImmutability();
return immutability == null ? null : f.apply(immutability);
}
String[] getParameterNames();
Relation getRelationship();
boolean isRelationship();
@Override
boolean isDeclaredBy(Class> clazz);
default String getRelationshipName() {
return applyToRelationship(Relation::getName);
}
default String getRelationshipResource(ResourceRegistry registry) {
return applyToRelationship(r -> r.getResource(registry));
}
default String getRelationshipJoinField() {
return applyToRelationship(Relation::getJoinField);
}
default RelationshipType getRelationshipType() {
return applyToRelationship(Relation::getType);
}
/**
* null safe. apply f to {@link #getRelationship()}
*
* @param result of function
* @param f function to apply to the relationship
* @return result of f
*/
default R applyToRelationship(Function f) {
Relation relation = getRelationship();
return relation == null ? null : f.apply(relation);
}
public final static class Builder {
private Type type;
private String beanName;
private String apiName;
private String persistedName;
private boolean apiProperty;
private boolean transientField;
private Identifier identifier;
private CaseSensitivity caseSensitivity;
private Relation relation;
private Immutability immutability;
private String[] parameterNames;
private Field field;
private Method getter;
private Method setter;
private Class> genericType;
public Builder(Type type) {
this.type = type;
}
private Builder me() {
return this;
}
public Builder field(Field field) {
this.field = makeAccessible(field);
return me();
}
public Builder getter(Method getter) {
this.getter = makeAccessible(getter);
return me();
}
public Builder setter(Method setter) {
this.setter = makeAccessible(setter);
return me();
}
@SuppressWarnings("rawtypes")
public Builder genericType(Type genericType) {
if (genericType instanceof Class) {
return genericType((Class) genericType);
}
return me();
}
public Builder genericType(Class> genericType) {
this.genericType = genericType;
return me();
}
public Builder apiProperty(boolean apiProperty) {
this.apiProperty = apiProperty;
return me();
}
public Builder transientField(boolean transientField) {
this.transientField = transientField;
return me();
}
public Builder immutable(Immutable immutable) {
return immutability(Immutability.getImmutability(immutable));
}
public Builder immutability(Immutability immutability) {
this.immutability = immutability;
return me();
}
public Builder> caseSensitiviteField(String searchField) {
return caseSensitivity(CaseSensitivity.builder()
.searchField(searchField));
}
public Builder caseInsensitive(CaseInsensitive caseInsensitive) {
return caseSensitivity(CaseSensitivity.getCaseSensitivity(caseInsensitive));
}
public Builder caseSensitivity(CaseSensitivity.Builder caseSensitivity) {
return caseSensitivity(caseSensitivity.build());
}
public Builder caseSensitivity(CaseSensitivity caseSensitivity) {
this.caseSensitivity = caseSensitivity;
return me();
}
public Builder relationship(Relationship relationship) {
return relation(Relation.getRelation(relationship));
}
public Builder relationshipTo(String resource) {
return relationshipTo(resource, "id");
}
public Builder relationshipTo(String resource, String joinField) {
return relation(Relation.builder()
.joinField(joinField)
.resource(resource).build());
}
public Builder relation(Relation relation) {
this.relation = relation;
return me();
}
public Builder param(Param param) {
return parameterNames(param == null ? null : param.value());
}
public Builder parameterNames(String... parameterNames) {
this.parameterNames = parameterNames;
return me();
}
public Builder identifier(Identifier identifier) {
this.identifier = identifier;
return me();
}
public Builder idField(boolean isIdField) {
return identifier(isIdField ? Identifier.builder().build() : null);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public MappedField build() {
if ( this.apiProperty ) {
Assert.notNull(apiProperty, "api name is required for api fields");
}
if ( ! this.transientField ) {
Assert.notNull(persistedName, "persisted name is required for non transient fields");
}
ReadableField readable = null;
WritableField writable = null;
if (readable == null) {
if (field != null) {
readable = ReflectMappedField.of(field);
} else if (getter != null && setter != null) {
readable = ReflectMappedMethod.of(getter, setter);
} else if (getter != null) {
readable = ReflectReadableMappedMethod.of(getter);
} else {
// if writable is explicitly configured (not null) then
// we will use setter or used default MapField readable
if (setter != null) {
writable = (WritableField) ReflectWritableMappedMethod.of(setter);
} else {
readable = MapField.of(beanName);
}
}
}
if (writable == null && readable instanceof WritableField) {
writable = (WritableField) readable;
}
Immutability immutability = this.immutability;
if (identifier != null && immutability == null) {
immutability = Immutability.builder().build();
}
if ( type instanceof Class ) {
Class clazz = (Class) type;
if (Iterable.class.isAssignableFrom(clazz)) {
boolean collection = Collection.class.isAssignableFrom(clazz);
return new BasicIterableField(clazz, beanName, apiName, persistedName, identifier, collection, apiProperty, transientField, caseSensitivity, relation, immutability, parameterNames, readable, writable, genericType);
}
}
return new BasicMappedField(type, beanName, apiName, persistedName, identifier, false, apiProperty, transientField, caseSensitivity, relation, immutability, parameterNames, readable, writable);
}
public void accept(MappedFieldBuilderVisitor[] visitors, BeanInfo bi,
PropertyDescriptor pd) {
// visit builders for customization
if (visitors != null) {
for (MappedFieldBuilderVisitor visitor : visitors) {
accept(visitor, bi, pd);
}
}
}
public void accept(MappedFieldBuilderVisitor visitor, BeanInfo bi,
PropertyDescriptor pd) {
visitor.visit(this, bi, pd);
}
public String getBeanName() {
return beanName;
}
public Builder beanName(String beanName) {
this.beanName = beanName;
return me();
}
public String getApiName() {
return apiName;
}
public Builder apiName(String apiName) {
this.apiName = apiName;
return apiProperty(StringUtils.isNotEmpty(apiName));
}
public String getPersistedName() {
return persistedName;
}
public Builder persistedName(String persistedName) {
this.persistedName = persistedName;
return transientField(StringUtils.isEmpty(persistedName));
}
public void anonymousMapping() {
this.beanName = nvl(beanName, apiName, persistedName);
if ( ! transientField ) {
persistedName = nvl(persistedName, beanName);
}
if ( apiProperty ) {
apiName = nvl(apiName, beanName);
}
}
private String nvl(String... vals) {
for (String s : vals) {
if ( StringUtils.isNotEmpty(s) ) {
return s;
}
}
return null;
}
}
}