/*
* Copyright 2014 - 2017 Blazebit.
*
* 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 com.blazebit.persistence.impl;
import com.blazebit.reflection.ReflectionUtils;
import javax.persistence.metamodel.Attribute;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Christian Beikov
* @since 1.2.0
*/
public class AssociationFromIdParameterTransformer implements ParameterManager.ParameterValueTranformer {
private static final Map<Class<?>, AssociationFromIdParameterTransformer> INSTANCES = new ConcurrentHashMap<>();
private final Constructor<Object> entityConstructor;
private final Field idField;
private final Method idSetter;
private AssociationFromIdParameterTransformer(Class<?> associationType, Attribute<?, ?> idAttribute) {
try {
Constructor<Object> constructor = (Constructor<Object>) associationType.getDeclaredConstructor();
constructor.setAccessible(true);
Member idMember = idAttribute.getJavaMember();
if (idMember instanceof Method) {
Method setter = ReflectionUtils.getSetter(associationType, idAttribute.getName());
setter.setAccessible(true);
this.idField = null;
this.idSetter = setter;
} else if (idMember instanceof Field) {
Field field = (Field) idMember;
field.setAccessible(true);
this.idField = field;
this.idSetter = null;
} else {
throw new IllegalArgumentException("Unsupported attribute member type [" + idMember + "] for attribute [" + idAttribute.getName() + "] of class [" + associationType.getName() + "]");
}
this.entityConstructor = constructor;
} catch (Exception e) {
throw new IllegalArgumentException("The entity type [" + associationType.getName() + "] does not have a default constructor or id field/setter!", e);
}
}
public static AssociationFromIdParameterTransformer getInstance(Class<?> associationType, Attribute<?, ?> idAttribute) {
AssociationFromIdParameterTransformer transformer = INSTANCES.get(associationType);
if (transformer == null) {
synchronized (INSTANCES) {
transformer = INSTANCES.get(associationType);
if (transformer == null) {
transformer = new AssociationFromIdParameterTransformer(associationType, idAttribute);
INSTANCES.put(associationType, transformer);
}
}
}
return transformer;
}
@Override
public Object transform(Object originalValue) {
try {
Object object = entityConstructor.newInstance();
if (idField != null) {
idField.set(object, originalValue);
} else {
idSetter.invoke(object, originalValue);
}
return object;
} catch (Exception ex) {
throw new IllegalArgumentException("Could not transform parameter value [" + originalValue + "] to entity object of type [" + entityConstructor.getDeclaringClass().getName() + "]", ex);
}
}
}