/* * Copyright 2012-2017 the original author or authors. * * 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 org.springframework.data.mapping.context; import lombok.NonNull; import lombok.RequiredArgsConstructor; import java.util.Collections; import java.util.Optional; import java.util.function.Function; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.support.IsNewStrategy; import org.springframework.data.support.IsNewStrategyFactory; import org.springframework.data.support.IsNewStrategyFactorySupport; import org.springframework.util.Assert; /** * An {@link IsNewStrategyFactory} using a {@link MappingContext} to determine the {@link IsNewStrategy} to be returned * for a particular type. It will look for a version and id property on the {@link PersistentEntity} and return a * strategy instance that will refelctively inspect the property for {@literal null} values or {@literal null} or a * value of 0 in case of a version property. * * @author Oliver Gierke * @author Christoph Strobl */ public class MappingContextIsNewStrategyFactory extends IsNewStrategyFactorySupport { private final PersistentEntities context; /** * Creates a new {@link MappingContextIsNewStrategyFactory} using the given {@link MappingContext}. * * @param context must not be {@literal null}. * @deprecated use {@link MappingContextIsNewStrategyFactory(PersistentEntities)} instead. */ @Deprecated public MappingContextIsNewStrategyFactory(MappingContext<? extends PersistentEntity<?, ?>, ?> context) { this(new PersistentEntities(Collections.singletonList(context))); } /** * Creates a new {@link MappingContextIsNewStrategyFactory} using the given {@link PersistentEntities}. * * @param context must not be {@literal null}. * @since 1.10 */ public MappingContextIsNewStrategyFactory(PersistentEntities entities) { Assert.notNull(entities, "PersistentEntities must not be null!"); this.context = entities; } /* * (non-Javadoc) * @see org.springframework.data.support.IsNewStrategyFactorySupport#getFallBackStrategy(java.lang.Class) */ @Override protected IsNewStrategy doGetIsNewStrategy(Class<?> type) { return context.getPersistentEntity(type)// .flatMap(MappingContextIsNewStrategyFactory::foo)// .orElseThrow(() -> new MappingException(String.format("Cannot determine IsNewStrategy for type %s!", type))); } private static Optional<IsNewStrategy> foo(PersistentEntity<?, ?> entity) { if (entity.hasVersionProperty()) { return entity.getVersionProperty().map(it -> PersistentPropertyInspectingIsNewStrategy.of(it, MappingContextIsNewStrategyFactory::propertyIsNullOrZeroNumber)); } else if (entity.hasIdProperty()) { return entity.getIdProperty().map( it -> PersistentPropertyInspectingIsNewStrategy.of(it, MappingContextIsNewStrategyFactory::propertyIsNull)); } return Optional.empty(); } /** * {@link IsNewStrategy} implementation that will inspect a given {@link PersistentProperty} and call * {@link #decideIsNew(Object)} with the value retrieved by reflection. * * @author Oliver Gierke */ @RequiredArgsConstructor(staticName = "of") static class PersistentPropertyInspectingIsNewStrategy implements IsNewStrategy { private final @NonNull PersistentProperty<?> property; private final @NonNull Function<Optional<Object>, Boolean> isNew; /* * (non-Javadoc) * @see org.springframework.data.support.IsNewStrategy#isNew(java.util.Optional) */ @Override public boolean isNew(Object entity) { Assert.notNull(entity, "Entity must not be null!"); return isNew.apply(property.getOwner().getPropertyAccessor(entity).getProperty(property)); } } private static boolean propertyIsNull(Optional<Object> it) { return !it.isPresent(); } private static boolean propertyIsNullOrZeroNumber(Optional<Object> it) { return it.map(value -> { if (!(value instanceof Number)) { return false; } return ((Number) value).longValue() == 0; }).orElse(true); } }