All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.evitadb.api.proxy.impl.referenceBuilder.SetReferenceAttributeMethodClassifier Maven / Gradle / Ivy

The newest version!
/*
 *
 *                         _ _        ____  ____
 *               _____   _(_) |_ __ _|  _ \| __ )
 *              / _ \ \ / / | __/ _` | | | |  _ \
 *             |  __/\ V /| | || (_| | |_| | |_) |
 *              \___| \_/ |_|\__\__,_|____/|____/
 *
 *   Copyright (c) 2023-2024
 *
 *   Licensed under the Business Source License, Version 1.1 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   https://github.com/FgForrest/evitaDB/blob/master/LICENSE
 *
 *   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 io.evitadb.api.proxy.impl.referenceBuilder;

import io.evitadb.api.proxy.impl.SealedEntityReferenceProxyState;
import io.evitadb.api.requestResponse.data.ReferenceEditor.ReferenceBuilder;
import io.evitadb.api.requestResponse.data.annotation.RemoveWhenExists;
import io.evitadb.api.requestResponse.schema.AttributeSchemaContract;
import io.evitadb.dataType.EvitaDataTypes;
import io.evitadb.utils.Assert;
import one.edee.oss.proxycian.CurriedMethodContextInvocationHandler;
import one.edee.oss.proxycian.DirectMethodClassification;
import one.edee.oss.proxycian.utils.GenericsUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;

import static io.evitadb.api.proxy.impl.MethodArgumentsParser.parseArguments;
import static io.evitadb.api.proxy.impl.reference.GetReferenceAttributeMethodClassifier.getAttributeSchema;

/**
 * Identifies methods that are used to set entity reference attributes into an entity and provides their implementation.
 *
 * @author Jan Novotný ([email protected]), FG Forrest a.s. (c) 2023
 */
public class SetReferenceAttributeMethodClassifier extends DirectMethodClassification {
	/**
	 * We may reuse singleton instance since advice is stateless.
	 */
	public static final SetReferenceAttributeMethodClassifier INSTANCE = new SetReferenceAttributeMethodClassifier();

	/**
	 * Provides implementation for setting attribute value from a single value returning a void return type.
	 *
	 * @param valueParameterPosition index of the value parameter among method parameters
	 * @param attributeName          name of the attribute to be set
	 * @param plainType              expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setAttributeAsValueWithVoidResult(
		int valueParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setAttributeAsValue(attributeName, plainType, theState, args[valueParameterPosition]);
			return null;
		};
	}

	/**
	 * Provides implementation for setting attribute value from a single value returning a proxy object return type
	 * allowing to create a builder pattern in the model objects.
	 *
	 * @param valueParameterPosition index of the value parameter among method parameters
	 * @param attributeName          name of the attribute to be set
	 * @param plainType              expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setAttributeAsValueWithBuilderResult(
		int valueParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setAttributeAsValue(attributeName, plainType, theState, args[valueParameterPosition]);
			return proxy;
		};
	}

	/**
	 * Sets the value of the specified attribute using a single value.
	 *
	 * @param attributeName The name of the associated data to be set.
	 * @param plainType     The expected type of the associated data.
	 * @param theState      The proxy state.
	 * @param value         The value to be set.
	 */
	private static void setAttributeAsValue(
		@Nonnull String attributeName,
		@Nonnull Class plainType,
		@Nonnull SealedEntityReferenceProxyState theState,
		@Nullable Object value
	) {
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		if (value == null) {
			referenceBuilder.removeAttribute(attributeName);
		} else {
			referenceBuilder.setAttribute(
				attributeName,
				EvitaDataTypes.toTargetType((Serializable) value, plainType)
			);
		}
	}

	/**
	 * Provides implementation for setting attribute array value from a collection value returning a void return type.
	 *
	 * @param valueParameterPosition index of the value parameter among method parameters
	 * @param attributeName          name of the attribute to be set
	 * @param plainType              expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setAttributeAsCollectionWithVoidResult(
		int valueParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setAttributeAsCollection(attributeName, plainType, theState, args[valueParameterPosition]);
			return null;
		};
	}

	/**
	 * Provides implementation for setting attribute array value from a collection value returning a proxy object
	 * return type allowing to create a builder pattern in the model objects.
	 *
	 * @param valueParameterPosition index of the value parameter among method parameters
	 * @param attributeName          name of the attribute to be set
	 * @param plainType              expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setAttributeAsCollectionWithBuilderResult(
		int valueParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setAttributeAsCollection(attributeName, plainType, theState, args[valueParameterPosition]);
			return proxy;
		};
	}

	/**
	 * Sets the value of the specified attribute using an array value.
	 *
	 * @param attributeName The name of the attribute to be set.
	 * @param plainType     The expected type of the attribute.
	 * @param theState      The proxy state.
	 * @param value         The value to be set.
	 */
	private static void setAttributeAsCollection(
		@Nonnull String attributeName,
		@Nonnull Class plainType,
		@Nonnull SealedEntityReferenceProxyState theState,
		@Nullable Object value
	) {
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		if (value == null) {
			referenceBuilder.removeAttribute(attributeName);
		} else {
			//noinspection unchecked,rawtypes
			referenceBuilder.setAttribute(
				attributeName,
				((Collection) value).stream()
					.map(it -> EvitaDataTypes.toTargetType((Serializable) it, plainType))
					.toArray(cnt -> Array.newInstance(plainType, cnt))
			);
		}
	}

	/**
	 * Provides implementation for setting localized attribute value from a single value returning a void return type.
	 *
	 * @param valueParameterPosition  index of the value parameter among method parameters
	 * @param localeParameterPosition index of the {@link Locale} parameter among method parameters
	 * @param attributeName           name of the attribute to be set
	 * @param plainType               expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setLocalizedAttributeAsValueWithVoidResult(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setLocalizedAttributeAsValue(valueParameterPosition, localeParameterPosition, attributeName, plainType, args, theState);
			return null;
		};
	}

	/**
	 * Provides implementation for setting localized attribute value from a single value returning the proxy object
	 * return type allowing to create a builder pattern in the model objects.
	 *
	 * @param valueParameterPosition  index of the value parameter among method parameters
	 * @param localeParameterPosition index of the {@link Locale} parameter among method parameters
	 * @param attributeName           name of the attribute to be set
	 * @param plainType               expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setLocalizedAttributeAsValueWithBuilderResult(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setLocalizedAttributeAsValue(valueParameterPosition, localeParameterPosition, attributeName, plainType, args, theState);
			return proxy;
		};
	}

	/**
	 * Sets the localized attribute value from a single value.
	 *
	 * @param valueParameterPosition  The index of the value parameter among the method parameters
	 * @param localeParameterPosition The index of the Locale parameter among the method parameters
	 * @param attributeName           The name of the attribute to be set.
	 * @param plainType               The expected type of the attribute.
	 * @param args                    The array of method arguments
	 * @param theState                The SealedEntityProxyState object
	 */
	private static void setLocalizedAttributeAsValue(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType,
		@Nonnull Object[] args,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final Object value = args[valueParameterPosition];
		final Locale locale = (Locale) args[localeParameterPosition];
		Assert.notNull(locale, "Locale must not be null!");
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		if (value == null) {
			referenceBuilder.removeAttribute(attributeName);
		} else {
			referenceBuilder.setAttribute(
				attributeName, locale,
				EvitaDataTypes.toTargetType((Serializable) value, plainType)
			);
		}
	}

	/**
	 * Provides implementation for setting localized attribute array value from a collection value returning a void
	 * return type.
	 *
	 * @param valueParameterPosition  index of the value parameter among method parameters
	 * @param localeParameterPosition index of the {@link Locale} parameter among method parameters
	 * @param attributeName           name of the attribute to be set
	 * @param plainType               expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setLocalizedAttributeAsCollectionWithVoidResult(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setLocalizedAttributeAsCollection(valueParameterPosition, localeParameterPosition, attributeName, plainType, args, theState);
			return null;
		};
	}

	/**
	 * Provides implementation for setting localized attribute array value from a collection value returning the proxy
	 * object return type allowing to create a builder pattern in the model objects.
	 *
	 * @param valueParameterPosition  index of the value parameter among method parameters
	 * @param localeParameterPosition index of the {@link Locale} parameter among method parameters
	 * @param attributeName           name of the attribute to be set
	 * @param plainType               expected type of the attribute
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler setLocalizedAttributeAsCollectionWithBuilderResult(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			setLocalizedAttributeAsCollection(valueParameterPosition, localeParameterPosition, attributeName, plainType, args, theState);
			return proxy;
		};
	}

	/**
	 * Sets the localized associated data as a collection value and returns the proxy object.
	 *
	 * @param valueParameterPosition  The index of the value parameter among the method parameters.
	 * @param localeParameterPosition The index of the Locale parameter among the method parameters.
	 * @param attributeName           The name of the attribute to be set.
	 * @param plainType               The expected type of the attribute.
	 * @param plainType               The expected type of the attribute.
	 * @param args                    The arguments passed to the method.
	 * @param theState                The SealedEntityProxyState object containing the entity state.
	 */
	private static void setLocalizedAttributeAsCollection(
		int valueParameterPosition,
		int localeParameterPosition,
		@Nonnull String attributeName,
		@Nonnull Class plainType,
		@Nonnull Object[] args,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final Object value = args[valueParameterPosition];
		final Locale locale = (Locale) args[localeParameterPosition];
		Assert.notNull(locale, "Locale must not be null!");
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		if (value == null) {
			referenceBuilder.removeAttribute(attributeName, locale);
		} else {
			//noinspection unchecked,rawtypes
			referenceBuilder.setAttribute(
				attributeName, locale,
				((Collection) value).stream()
					.map(it -> EvitaDataTypes.toTargetType((Serializable) it, plainType))
					.toArray(cnt -> Array.newInstance(plainType, cnt))
			);
		}
	}

	/**
	 * Provides implementation for removing localized attribute value returning the proxy object return type allowing
	 * to create a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeLocalizedAttributeWithBuilderResult(
		@Nonnull String attributeName
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			removeLocalizedAttribute(attributeName, args, theState);
			return proxy;
		};
	}

	/**
	 * Provides implementation for removing localized attribute value returning a void return type.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeLocalizedAttributeWithVoidResult(
		@Nonnull String attributeName
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			removeLocalizedAttribute(attributeName, args, theState);
			return null;
		};
	}

	/**
	 * Provides implementation for removing localized attribute value returning the proxy object return type allowing
	 * to create a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeLocalizedAttributeWithValueCollectionResult(
		@Nonnull String attributeName,
		@Nonnull Class schemaType,
		@Nonnull Class plainType
	) {
		Assert.isTrue(
			schemaType.isArray(),
			"Localized attribute `" + attributeName + "` must be an array in order collection could be returned!"
		);
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			final Object[] removedArray = (Object[]) removeLocalizedAttributeAndReturnIt(attributeName, args, theState);
			return Arrays.stream(removedArray).map(it -> EvitaDataTypes.toTargetType((Serializable) it, plainType)).toList();
		};
	}

	/**
	 * Provides implementation for removing localized attribute value returning the proxy object return type allowing
	 * to create a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeLocalizedAttributeWithValueResult(
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> EvitaDataTypes.toTargetType(
			removeLocalizedAttributeAndReturnIt(attributeName, args, theState), plainType
		);
	}

	/**
	 * Removes localized attribute from the entity.
	 *
	 * @param attributeName name of the attribute to be set
	 * @param args          method arguments
	 * @param theState      proxy state
	 */
	private static void removeLocalizedAttribute(
		@Nonnull String attributeName,
		@Nonnull Object[] args,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final Locale locale = (Locale) args[0];
		Assert.notNull(locale, "Locale must not be null!");
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		referenceBuilder.removeAttribute(attributeName, locale);
	}

	/**
	 * Removes localized attribute from the entity and returns its value.
	 *
	 * @param attributeName name of the attribute to be set
	 * @param args          method arguments
	 * @param theState      proxy state
	 */
	@Nullable
	private static Serializable removeLocalizedAttributeAndReturnIt(
		@Nonnull String attributeName,
		@Nonnull Object[] args,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final Locale locale = (Locale) args[0];
		Assert.notNull(locale, "Locale must not be null!");
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		final Serializable attributeToRemove = referenceBuilder.getAttribute(attributeName, locale);
		if (attributeToRemove != null) {
			referenceBuilder.removeAttribute(attributeName, locale);
			return attributeToRemove;
		} else {
			return null;
		}
	}

	/**
	 * Provides implementation for removing attribute value returning the proxy object return type allowing to create
	 * a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeAttributeWithBuilderResult(
		@Nonnull String attributeName
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			removeAttribute(attributeName, theState);
			return proxy;
		};
	}

	/**
	 * Provides implementation for removing attribute value returning a void return type.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeAttributeWithVoidResult(
		@Nonnull String attributeName
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			removeAttribute(attributeName, theState);
			return null;
		};
	}

	/**
	 * Provides implementation for removing attribute value returning the proxy object return type allowing to create
	 * a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeAttributeWithValueCollectionResult(
		@Nonnull String attributeName,
		@Nonnull Class schemaType,
		@Nonnull Class plainType
	) {
		Assert.isTrue(
			schemaType.isArray(),
			" attribute `" + attributeName + "` must be an array in order collection could be returned!"
		);
		return (proxy, theMethod, args, theState, invokeSuper) -> {
			final Object[] removedArray = (Object[]) removeAttributeAndReturnIt(attributeName, theState);
			return Arrays.stream(removedArray).map(it -> EvitaDataTypes.toTargetType((Serializable) it, plainType)).toList();
		};
	}

	/**
	 * Provides implementation for removing attribute value returning the proxy object return type allowing to create
	 * a builder pattern in the model objects.
	 *
	 * @param attributeName name of the attribute to be set
	 * @return implementation of the method call
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	@Nonnull
	private static CurriedMethodContextInvocationHandler removeAttributeWithValueResult(
		@Nonnull String attributeName,
		@Nonnull Class plainType
	) {
		return (proxy, theMethod, args, theState, invokeSuper) -> EvitaDataTypes.toTargetType(
			removeAttributeAndReturnIt(attributeName, theState), plainType
		);
	}

	/**
	 * Removes  attribute from the entity.
	 *
	 * @param attributeName name of the attribute to be set
	 * @param theState      proxy state
	 */
	private static void removeAttribute(
		@Nonnull String attributeName,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		referenceBuilder.removeAttribute(attributeName);
	}

	/**
	 * Removes  attribute from the entity and returns its value.
	 *
	 * @param attributeName name of the attribute to be set
	 * @param theState      proxy state
	 */
	@Nullable
	private static Serializable removeAttributeAndReturnIt(
		@Nonnull String attributeName,
		@Nonnull SealedEntityReferenceProxyState theState
	) {
		final ReferenceBuilder referenceBuilder = theState.getReferenceBuilder();
		final Serializable attributeToRemove = referenceBuilder.getAttribute(attributeName);
		if (attributeToRemove != null) {
			referenceBuilder.removeAttribute(attributeName);
			return attributeToRemove;
		} else {
			return null;
		}
	}

	public SetReferenceAttributeMethodClassifier() {
		super(
			"setReferenceAttribute",
			(method, proxyState) -> parseArguments(
				method,
				argType -> (EvitaDataTypes.isSupportedTypeOrItsArrayOrEnum(argType)) || EvitaDataTypes.isEnumOrArrayOfEnums(argType) || Collection.class.isAssignableFrom(argType)
			)
				.map(
					parsedArguments -> {
						// now we need to identify attribute schema that is being requested
						final AttributeSchemaContract attributeSchema = getAttributeSchema(
							method, proxyState.getReflectionLookup(),
							proxyState.getEntitySchema(),
							proxyState.getReferenceSchema()
						);
						// if not found, this method is not classified by this implementation
						if (attributeSchema == null) {
							return null;
						} else {
							// finally provide implementation that will retrieve the attribute from the entity
							final String attributeName = attributeSchema.getName();
							if (attributeSchema.isLocalized()) {
								Assert.isTrue(
									parsedArguments.localeParameterPosition().isPresent(),
									"Localized attribute `" + attributeSchema.getName() + "` must have a locale parameter!"
								);
								if (method.isAnnotationPresent(RemoveWhenExists.class)) {
									if (method.getReturnType().equals(proxyState.getProxyClass())) {
										return removeLocalizedAttributeWithBuilderResult(attributeName);
									} else if (method.getReturnType().equals(void.class)) {
										return removeLocalizedAttributeWithVoidResult(attributeName);
									} else if (Collection.class.isAssignableFrom(method.getReturnType())) {
										return removeLocalizedAttributeWithValueCollectionResult(
											attributeName,
											attributeSchema.getType(),
											GenericsUtils.getMethodReturnType(proxyState.getProxyClass(), method)
										);
									} else {
										return removeLocalizedAttributeWithValueResult(attributeName, method.getReturnType());
									}
								} else {
									// now we need to identify the argument type
									final Parameter valueParameter = method.getParameters()[parsedArguments.valueParameterPosition()];
									if (Collection.class.isAssignableFrom(valueParameter.getType())) {
										if (method.getReturnType().equals(proxyState.getProxyClass())) {
											return setLocalizedAttributeAsCollectionWithBuilderResult(
												parsedArguments.valueParameterPosition(),
												parsedArguments.localeParameterPosition().getAsInt(),
												attributeName,
												attributeSchema.getPlainType()
											);
										} else {
											return setLocalizedAttributeAsCollectionWithVoidResult(
												parsedArguments.valueParameterPosition(),
												parsedArguments.localeParameterPosition().getAsInt(),
												attributeName,
												attributeSchema.getPlainType()
											);
										}
									} else {
										if (method.getReturnType().equals(proxyState.getProxyClass())) {
											return setLocalizedAttributeAsValueWithBuilderResult(
												parsedArguments.valueParameterPosition(),
												parsedArguments.localeParameterPosition().getAsInt(),
												attributeName,
												attributeSchema.getPlainType()
											);
										} else {
											return setLocalizedAttributeAsValueWithVoidResult(
												parsedArguments.valueParameterPosition(),
												parsedArguments.localeParameterPosition().getAsInt(),
												attributeName,
												attributeSchema.getPlainType()
											);
										}
									}
								}
							} else {
								if (method.isAnnotationPresent(RemoveWhenExists.class)) {
									Assert.isTrue(
										method.getParameterCount() == 0,
										"Non-localized attribute `" + attributeSchema.getName() + "` must not have a locale parameter!"
									);

									if (method.getReturnType().equals(proxyState.getProxyClass())) {
										return removeAttributeWithBuilderResult(attributeName);
									} else if (method.getReturnType().equals(void.class)) {
										return removeAttributeWithVoidResult(attributeName);
									} else if (Collection.class.isAssignableFrom(method.getReturnType())) {
										return removeAttributeWithValueCollectionResult(
											attributeName,
											attributeSchema.getType(),
											GenericsUtils.getMethodReturnType(proxyState.getProxyClass(), method)
										);
									} else {
										return removeAttributeWithValueResult(attributeName, method.getReturnType());
									}
								} else {
									Assert.isTrue(
										method.getParameterCount() == 1,
										"Non-localized attribute `" + attributeSchema.getName() + "` must not have a locale parameter!"
									);

									// now we need to identify the argument type
									final Parameter valueParameter = method.getParameters()[parsedArguments.valueParameterPosition()];
									if (Collection.class.isAssignableFrom(valueParameter.getType())) {
										if (method.getReturnType().equals(proxyState.getProxyClass())) {
											return setAttributeAsCollectionWithBuilderResult(
												parsedArguments.valueParameterPosition(), attributeName, attributeSchema.getPlainType()
											);
										} else {
											return setAttributeAsCollectionWithVoidResult(
												parsedArguments.valueParameterPosition(), attributeName, attributeSchema.getPlainType()
											);
										}
									} else {
										if (method.getReturnType().equals(proxyState.getProxyClass())) {
											return setAttributeAsValueWithBuilderResult(
												parsedArguments.valueParameterPosition(), attributeName, attributeSchema.getPlainType()
											);
										} else {
											return setAttributeAsValueWithVoidResult(
												parsedArguments.valueParameterPosition(), attributeName, attributeSchema.getPlainType()
											);
										}
									}
								}
							}
						}
					})
				.orElse(null)
		);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy