001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.autoconfigure.orm.jpa;
018
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.function.Supplier;
023
024import org.hibernate.cfg.AvailableSettings;
025
026import org.springframework.boot.context.properties.ConfigurationProperties;
027import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
028import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
029import org.springframework.util.Assert;
030import org.springframework.util.ObjectUtils;
031import org.springframework.util.StringUtils;
032
033/**
034 * Configuration properties for Hibernate.
035 *
036 * @author Stephane Nicoll
037 * @since 2.1.0
038 * @see JpaProperties
039 */
040@ConfigurationProperties("spring.jpa.hibernate")
041public class HibernateProperties {
042
043        private final Naming naming = new Naming();
044
045        /**
046         * DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property.
047         * Defaults to "create-drop" when using an embedded database and no schema manager was
048         * detected. Otherwise, defaults to "none".
049         */
050        private String ddlAuto;
051
052        /**
053         * Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
054         * This is actually a shortcut for the "hibernate.id.new_generator_mappings" property.
055         * When not specified will default to "true".
056         */
057        private Boolean useNewIdGeneratorMappings;
058
059        public String getDdlAuto() {
060                return this.ddlAuto;
061        }
062
063        public void setDdlAuto(String ddlAuto) {
064                this.ddlAuto = ddlAuto;
065        }
066
067        public Boolean isUseNewIdGeneratorMappings() {
068                return this.useNewIdGeneratorMappings;
069        }
070
071        public void setUseNewIdGeneratorMappings(Boolean useNewIdGeneratorMappings) {
072                this.useNewIdGeneratorMappings = useNewIdGeneratorMappings;
073        }
074
075        public Naming getNaming() {
076                return this.naming;
077        }
078
079        /**
080         * Determine the configuration properties for the initialization of the main Hibernate
081         * EntityManagerFactory based on standard JPA properties and
082         * {@link HibernateSettings}.
083         * @param jpaProperties standard JPA properties
084         * @param settings the settings to apply when determining the configuration properties
085         * @return the Hibernate properties to use
086         */
087        public Map<String, Object> determineHibernateProperties(
088                        Map<String, String> jpaProperties, HibernateSettings settings) {
089                Assert.notNull(jpaProperties, "JpaProperties must not be null");
090                Assert.notNull(settings, "Settings must not be null");
091                return getAdditionalProperties(jpaProperties, settings);
092        }
093
094        private Map<String, Object> getAdditionalProperties(Map<String, String> existing,
095                        HibernateSettings settings) {
096                Map<String, Object> result = new HashMap<>(existing);
097                applyNewIdGeneratorMappings(result);
098                getNaming().applyNamingStrategies(result);
099                String ddlAuto = determineDdlAuto(existing, settings::getDdlAuto);
100                if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) {
101                        result.put(AvailableSettings.HBM2DDL_AUTO, ddlAuto);
102                }
103                else {
104                        result.remove(AvailableSettings.HBM2DDL_AUTO);
105                }
106                Collection<HibernatePropertiesCustomizer> customizers = settings
107                                .getHibernatePropertiesCustomizers();
108                if (!ObjectUtils.isEmpty(customizers)) {
109                        customizers.forEach((customizer) -> customizer.customize(result));
110                }
111                return result;
112        }
113
114        private void applyNewIdGeneratorMappings(Map<String, Object> result) {
115                if (this.useNewIdGeneratorMappings != null) {
116                        result.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS,
117                                        this.useNewIdGeneratorMappings.toString());
118                }
119                else if (!result.containsKey(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS)) {
120                        result.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true");
121                }
122        }
123
124        private String determineDdlAuto(Map<String, String> existing,
125                        Supplier<String> defaultDdlAuto) {
126                String ddlAuto = existing.get(AvailableSettings.HBM2DDL_AUTO);
127                if (ddlAuto != null) {
128                        return ddlAuto;
129                }
130                return (this.ddlAuto != null) ? this.ddlAuto : defaultDdlAuto.get();
131        }
132
133        public static class Naming {
134
135                /**
136                 * Fully qualified name of the implicit naming strategy.
137                 */
138                private String implicitStrategy;
139
140                /**
141                 * Fully qualified name of the physical naming strategy.
142                 */
143                private String physicalStrategy;
144
145                public String getImplicitStrategy() {
146                        return this.implicitStrategy;
147                }
148
149                public void setImplicitStrategy(String implicitStrategy) {
150                        this.implicitStrategy = implicitStrategy;
151                }
152
153                public String getPhysicalStrategy() {
154                        return this.physicalStrategy;
155                }
156
157                public void setPhysicalStrategy(String physicalStrategy) {
158                        this.physicalStrategy = physicalStrategy;
159                }
160
161                private void applyNamingStrategies(Map<String, Object> properties) {
162                        applyNamingStrategy(properties, AvailableSettings.IMPLICIT_NAMING_STRATEGY,
163                                        this.implicitStrategy, SpringImplicitNamingStrategy.class.getName());
164                        applyNamingStrategy(properties, AvailableSettings.PHYSICAL_NAMING_STRATEGY,
165                                        this.physicalStrategy, SpringPhysicalNamingStrategy.class.getName());
166                }
167
168                private void applyNamingStrategy(Map<String, Object> properties, String key,
169                                Object strategy, Object defaultStrategy) {
170                        if (strategy != null) {
171                                properties.put(key, strategy);
172                        }
173                        else if (defaultStrategy != null && !properties.containsKey(key)) {
174                                properties.put(key, defaultStrategy);
175                        }
176                }
177
178        }
179
180}