/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink * * 30/05/2012-2.4 Guy Pelletier * - 354678: Temp classloader is still being used during metadata processing ******************************************************************************/ package org.eclipse.persistence.mappings.converters; import java.security.AccessController; import java.security.PrivilegedActionException; import java.util.EnumSet; import java.util.Iterator; import org.eclipse.persistence.exceptions.ValidationException; import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; import org.eclipse.persistence.internal.security.PrivilegedClassForName; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.sessions.Session; /** * <b>Purpose</b>: Object type converter is used to match a fixed number of * database data values to a Java enum object value. It can be used when the * values on the database and in the Java differ. To create an object type * converter, simply specify the set of conversion value pairs. A default value * and one-way conversion are also supported for legacy data situations. * * @author Guy Pelletier * @since Toplink 10.1.4RI */ public class EnumTypeConverter extends ObjectTypeConverter { private Class m_enumClass; private String m_enumClassName; private boolean m_useOrdinalValues; /** * PUBLIC: * Creating an enum converter this way will create the conversion values * for you using ordinal or name values. */ public EnumTypeConverter(DatabaseMapping mapping, Class enumClass, boolean useOrdinalValues) { super(mapping); m_enumClass = enumClass; m_enumClassName = enumClass.getName(); m_useOrdinalValues = useOrdinalValues; initializeConversions(m_enumClass); } /** * PUBLIC: * Creating an enum converter this way will create the conversion values * for you using ordinal or name values. */ public EnumTypeConverter(DatabaseMapping mapping, String enumClassName, boolean useOrdinalValues) { this(mapping, enumClassName); m_useOrdinalValues = useOrdinalValues; } /** * PUBLIC: * Creating an enum converter this way expects that you will provide * the conversion values separately. */ public EnumTypeConverter(DatabaseMapping mapping, String enumClassName) { super(mapping); m_enumClassName = enumClassName; } protected void initializeConversions(Class enumClass) { // Initialize conversion if not already set by Converter if (getFieldToAttributeValues().isEmpty()) { EnumSet theEnums = EnumSet.allOf(enumClass); Iterator<Enum> i = theEnums.iterator(); while (i.hasNext()) { Enum theEnum = i.next(); if (m_useOrdinalValues) { addConversionValue(theEnum.ordinal(), theEnum.name()); } else { addConversionValue(theEnum.name(), theEnum.name()); } } } } public Class getEnumClass() { return m_enumClass; } public String getEnumClassName() { return m_enumClassName; } /** * INTERNAL: * Convert all the class-name-based settings in this converter to actual * class-based settings. This method is used when converting a project * that has been built with class names to a project with classes. * @param classLoader */ @Override public void convertClassNamesToClasses(ClassLoader classLoader) { super.convertClassNamesToClasses(classLoader); // convert if enumClass is null or if different classLoader if (m_enumClass == null || !m_enumClass.getClassLoader().equals(classLoader)) { try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { m_enumClass = AccessController.doPrivileged( new PrivilegedClassForName(m_enumClassName, true, classLoader)); } catch (PrivilegedActionException exception) { throw ValidationException.classNotFoundWhileConvertingClassNames( m_enumClassName, exception.getException()); } } else { m_enumClass = PrivilegedAccessHelper.getClassForName(m_enumClassName, true, classLoader); } } catch (ClassNotFoundException exception){ throw ValidationException.classNotFoundWhileConvertingClassNames(m_enumClassName, exception); } } initializeConversions(m_enumClass); } /** * INTERNAL: * Returns the corresponding attribute value for the specified field value. * Wraps the super method to return an Enum type from the string conversion. */ @Override public Object convertDataValueToObjectValue(Object fieldValue, Session session) { Object obj = super.convertDataValueToObjectValue(fieldValue, session); if (fieldValue == null || obj == null) { return obj; } else { return Enum.valueOf(m_enumClass, (String) obj); } } /** * INTERNAL: * Convert Enum object to the data value. Internal enums are stored as * strings (names) so this method wraps the super method in that if * breaks down the enum to a string name before converting it. */ @Override public Object convertObjectValueToDataValue(Object attributeValue, Session session) { if (attributeValue == null) { return super.convertObjectValueToDataValue(null, session); } else { return super.convertObjectValueToDataValue(((Enum)attributeValue).name(), session); } } }