/** * * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved. * * 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.speedment.plugins.enums; import com.speedment.common.injector.Injector; import com.speedment.common.injector.annotation.Inject; import com.speedment.common.lazy.specialized.LazyClass; import com.speedment.plugins.enums.internal.EnumGeneratorUtil; import com.speedment.plugins.enums.internal.GeneratedEnumType; import com.speedment.runtime.config.Column; import com.speedment.runtime.typemapper.TypeMapper; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.stream.Stream; import static com.speedment.plugins.enums.internal.GeneratedEntityDecorator.FROM_DATABASE_METHOD; import static com.speedment.plugins.enums.internal.GeneratedEntityDecorator.TO_DATABASE_METHOD; import static java.util.Objects.requireNonNull; /** * * @param <T> the enum type * * @author Emil Forslund * @author Simon Jonasson * @since 1.0.0 */ public final class StringToEnumTypeMapper<T extends Enum<T>> implements TypeMapper<String, T> { private final LazyClass cachedEnum; private @Inject Injector injector; public StringToEnumTypeMapper() { cachedEnum = LazyClass.create(); } public LazyClass getLazy() {return cachedEnum;} @Override public String getLabel() { return "String to Enum"; } @Override public Type getJavaType(Column column) { requireNonNull(injector, StringToEnumTypeMapper.class.getSimpleName() + ".getJavaType(Column) is not available if instantiated without injector." ); return new GeneratedEnumType( EnumGeneratorUtil.enumNameOf(column, injector), EnumGeneratorUtil.enumConstantsOf(column) ); } @Override public T toJavaType(Column column, Class<?> entityType, String value) { if (value == null) { return null; } else { final Class<?> enumClass = cachedEnum.getOrCompute( () -> EnumGeneratorUtil.classesIn(entityType) // Include only enum subclasses .filter(Enum.class::isAssignableFrom) // Include only enums with the correct name .filter(c -> c.getSimpleName().equalsIgnoreCase( column.getJavaName().replace("_", "") )) // Include only enums with a method called fromDatabase() // that takes the right parameters .filter(c -> Stream.of(c.getMethods()) .filter(m -> m.getName().equals("fromDatabase")) .filter(m -> { final Class<?>[] params = m.getParameterTypes(); return params.length == 1 && params[0] == column.findDatabaseType(); }) .findAny().isPresent() ) // Return it as the enumClass or throw an exception. .findAny() .orElse(null) ); final Method fromDatabase; try { fromDatabase = enumClass.getMethod(FROM_DATABASE_METHOD, String.class); } catch (final NoSuchMethodException ex) { throw new RuntimeException( "Could not find generated '" + FROM_DATABASE_METHOD + "'-method in enum class '" + enumClass.getName() + "'.", ex ); } try { @SuppressWarnings("unchecked") final T result = (T) fromDatabase.invoke(null, value); return result; } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { throw new RuntimeException( "Error executing '" + FROM_DATABASE_METHOD + "' in generated enum class '" + enumClass.getName() + "'.", ex ); } } } @Override public String toDatabaseType(T constant) { if (constant == null) { return null; } else { final Class<?> enumClass = constant.getClass(); final Method toDatabase; try { toDatabase = enumClass.getMethod(TO_DATABASE_METHOD); } catch (final NoSuchMethodException ex) { throw new RuntimeException( "Could not find generated '" + TO_DATABASE_METHOD + "'-method in enum class '" + constant.getClass().getName() + "'.", ex ); } try { @SuppressWarnings("unchecked") final String result = (String) toDatabase.invoke(constant); return result; } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { throw new RuntimeException( "Error executing '" + TO_DATABASE_METHOD + "' in generated enum class '" + constant.getClass().getName() + "'.", ex ); } } } }