All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.optional.OptionalEntity Maven / Gradle / Ivy

/*
 * Copyright 2014-2020 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.dbflute.optional;

import org.dbflute.exception.EntityAlreadyDeletedException;
import org.dbflute.exception.NonSetupSelectRelationAccessException;
import org.dbflute.helper.message.ExceptionMessageBuilder;

/**
 * The entity as optional object, which has entity instance in it. 
* You can handle null value by this methods without direct null handling. *
 * // if the data always exists as your business rule
 * memberBhv.selectEntity(cb -> {
 *     cb.setupSelect_MemberStatus();
 *     cb.query().setMemberId_Equal(1);
 * }).alwaysPresent(member -> {
 *     // called if present, or exception
 *     ... = member.getMemberName();
 * });
 *
 * // if it might be no data, ...
 * memberBhv.selectEntity(cb -> cb.acceptPK(1)).ifPresent(member -> {
 *     // called if present
 *     ... = member.getMemberName();
 * }).orElse(() -> {
 *     // called if not present
 * });
 * 
* @param The type of entity. * @author jflute * @since 1.0.5F (2014/05/05 Monday) */ public class OptionalEntity extends BaseOptional { // =================================================================================== // Definition // ========== private static final long serialVersionUID = 1L; // basically for relation entity's optional protected static final OptionalEntity EMPTY_INSTANCE; static { EMPTY_INSTANCE = new OptionalEntity(null, new SerializableOptionalThingExceptionThrower() { private static final long serialVersionUID = 1L; public void throwNotFoundException() { String msg = "The empty optional so the value is null."; throw new EntityAlreadyDeletedException(msg); } }); } protected static final OptionalThingExceptionThrower NOWAY_THROWER = new SerializableOptionalThingExceptionThrower() { private static final long serialVersionUID = 1L; @Override public void throwNotFoundException() { throw new EntityAlreadyDeletedException("no way"); } }; // =================================================================================== // Constructor // =========== /** * @param entity The wrapped instance of entity. (NullAllowed) * @param thrower The exception thrower when illegal access. (NotNull) */ public OptionalEntity(ENTITY entity, OptionalThingExceptionThrower thrower) { // basically called by DBFlute super(entity, thrower); } /** * @param The type of empty optional entity. * @return The fixed instance as empty. (NotNull) */ @SuppressWarnings("unchecked") public static OptionalEntity empty() { return (OptionalEntity) EMPTY_INSTANCE; } /** * @param The type of entity wrapped in the optional entity. * @param entity The wrapped entity for the optional object. (NotNull) * @return The new-created instance as existing optional object. (NotNull) */ public static OptionalEntity of(ENTITY entity) { if (entity == null) { String msg = "The argument 'entity' should not be null."; throw new IllegalArgumentException(msg); } return new OptionalEntity(entity, NOWAY_THROWER); } /** * @param The type of entity for the optional type. * @param entity The wrapped instance or entity. (NullAllowed) * @param noArgLambda The exception thrower when illegal access. (NotNull) * @return The new-created instance as existing or empty optional object. (NotNull) */ public static OptionalEntity ofNullable(ENTITY entity, OptionalThingExceptionThrower noArgLambda) { if (entity != null) { return of(entity); } else { return new OptionalEntity(entity, noArgLambda); } } /** * @param The type of empty optional entity. * @param entity The base entity of the relation for exception message. (NotNull) * @param relation The property name of the relation for exception message. (NotNull) * @return The new-created instance as existing or empty optional object. (NotNull) */ public static OptionalEntity relationEmpty(final Object entity, final String relation) { if (entity == null) { String msg = "The argument 'entity' should not be null."; throw new IllegalArgumentException(msg); } if (relation == null) { String msg = "The argument 'relation' should not be null."; throw new IllegalArgumentException(msg); } return new OptionalEntity(null, new OptionalThingExceptionThrower() { public void throwNotFoundException() { throwNonSetupSelectRelationAccessException(entity, relation); } }); } protected static void throwNonSetupSelectRelationAccessException(Object entity, String relation) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Non-setupSelect relation was accessed."); br.addItem("Advice"); br.addElement("Confirm your access to the relation."); br.addElement("Call setupSelect or fix your access."); br.addElement("For example:"); br.addElement(" (x):"); br.addElement(" memberBhv.selectList(cb -> {"); br.addElement(" cb.setupSelect_MemberStatus();"); br.addElement(" }).forEach(member -> {"); br.addElement(" ... = member.getMemberSecurityAsOne().alwaysPresent(...); // *NG"); br.addElement(" });"); br.addElement(" (o): (fix access mistake)"); br.addElement(" List memberList = memberBhv.selectList(cb -> {"); br.addElement(" cb.setupSelect_MemberStatus();"); br.addElement(" }).forEach(member -> {"); br.addElement(" ... = member.getMemberStatus().alwaysPresent(...); // OK"); br.addElement(" });"); br.addElement(" (o): (fix setupSelect mistake)"); br.addElement(" List memberList = memberBhv.selectList(cb -> {"); br.addElement(" cb.setupSelect_MemberSecurityAsOne(); // OK"); br.addElement(" }).forEach(member -> {"); br.addElement(" ... = member.getMemberSecurityAsOne().alwaysPresent(...);"); br.addElement(" });"); br.addItem("Your Relation"); br.addElement(entity.getClass().getSimpleName() + "." + relation); final String msg = br.buildExceptionMessage(); throw new NonSetupSelectRelationAccessException(msg); } // =================================================================================== // Standard Handling // ================= /** * Handle the wrapped entity if it is present.
* You should call this if null entity handling is unnecessary (do nothing if null).
* If exception is preferred when null entity, use required(). *
     * memberBhv.selectEntity(cb -> {
     *     cb.setupSelect_MemberWithdrawal();
     *     cb.query().setMemberId_Equal(1);
     * }).ifPresent(member -> { // called if value exists, or not called
     *     ... = member.getMemberName();
     *     member.getMemberWithdrawal().ifPresent(withdrawal -> { // also relation
     *         ... = withdrawal.getWithdrawalDatetime();
     *     });
     * }).orElse(() -> {
     *     // called if no value
     * });
     * 
* @param entityLambda The callback interface to consume the optional entity. (NotNull) * @return The handler of after process when if not present. (NotNull) */ public OptionalThingIfPresentAfter ifPresent(OptionalThingConsumer entityLambda) { assertEntityLambdaNotNull(entityLambda); return callbackIfPresent(entityLambda); } /** * Is the entity instance present? (existing?) *
     * OptionalEntity<Member> optMember = memberBhv.selectEntity(cb -> {
     *     cb.query()...;
     * });
     * if (optMember.isPresent()) { // true if the entity exists
     *     Member member = optMember.get();
     * } else {
     *     ...
     * }
     * 
* @return The determination, true or false. */ public boolean isPresent() { return exists(); } /** * Get the entity or exception if null. *
     * OptionalEntity<Member> optMember = memberBhv.selectEntity(cb -> {
     *     cb.setupSelect_MemberStatus();
     *     cb.query().setMemberId_Equal(1);
     * });
     *
     * // if the data always exists as your business rule
     * Member member = optMember.get();
     *
     * // if it might be no data, isPresent(), orElse(), ...
     * if (optMember.isPresent()) {
     *     Member member = optMember.get();
     * } else {
     *     ...
     * }
     * 
* @return The entity instance wrapped in this optional object. (NotNull) * @throws EntityAlreadyDeletedException When the entity instance wrapped in this optional object is null, which means entity has already been deleted (point is not found). */ public ENTITY get() { return directlyGet(); } /** * Filter the entity by the predicate. *
     * memberBhv.selectEntity(cb -> cb.acceptPK(1)).filter(member -> {
     *     // called if value exists, not called if not present
     *     return member.getMemberId() % 2 == 0;
     * }).ifPresent(member -> {
     *     ...
     * });
     * 
* @param entityLambda The callback to predicate whether the entity is remained. (NotNull) * @return The filtered optional entity, might be empty. (NotNull) */ public OptionalEntity filter(OptionalThingPredicate entityLambda) { assertEntityLambdaNotNull(entityLambda); return (OptionalEntity) callbackFilter(entityLambda); } /** {@inheritDoc} */ protected OptionalEntity createOptionalFilteredObject(ARG obj) { return new OptionalEntity(obj, _thrower); } /** * Apply the mapping of entity to result object. *
     * memberBhv.selectEntity(cb -> cb.acceptPK(1)).map(member -> {
     *     // called if value exists, not called if not present
     *     return new MemberWebBean(member);
     * }).alwaysPresent(member -> {
     *     ...
     * });
     * 
* @param The type of mapping result. * @param entityLambda The callback interface to apply, null return allowed as empty. (NotNull) * @return The optional thing as mapped result. (NotNull, EmptyOptionalAllowed: if not present or callback returns null) */ @SuppressWarnings("unchecked") public OptionalEntity map(OptionalThingFunction entityLambda) { assertEntityLambdaNotNull(entityLambda); return (OptionalEntity) callbackMapping(entityLambda); // downcast allowed because factory is overridden } /** {@inheritDoc} */ protected OptionalEntity createOptionalMappedObject(ARG obj) { return new OptionalEntity(obj, _thrower); } /** * Apply the flat-mapping of entity to result object. *
     * memberBhv.selectEntity(cb -> cb.acceptPK(1)).flatMap(member -> {
     *     // called if value exists, not called if not present
     *     return member.getMemberWithdrawal();
     * }).ifPresent(withdrawal -> {
     *     ...
     * });
     * 
* @param The type of mapping result. * @param entityLambda The callback interface to apply, cannot return null. (NotNull) * @return The optional thing as mapped result. (NotNull, EmptyOptionalAllowed: when not present) */ public OptionalThing flatMap(OptionalThingFunction> entityLambda) { assertEntityLambdaNotNull(entityLambda); return callbackFlatMapping(entityLambda); } /** {@inheritDoc} */ protected OptionalEntity createOptionalFlatMappedObject(ARG obj) { return new OptionalEntity(obj, _thrower); } // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // following methods might be rare case... // _/_/_/_/_/_/_/_/_/_/ /** {@inheritDoc} */ public ENTITY orElse(ENTITY other) { return directlyGetOrElse(other); } /** {@inheritDoc} */ public ENTITY orElseGet(OptionalThingSupplier noArgLambda) { return directlyGetOrElseGet(noArgLambda); } /** {@inheritDoc} */ public ENTITY orElseThrow(OptionalThingSupplier noArgLambda) throws CAUSE { return directlyGetOrElseThrow(noArgLambda); } /** {@inheritDoc} */ public ENTITY orElseTranslatingThrow( OptionalThingFunction oneArgLambda) throws TRANSLATED { return directlyGetOrElseTranslatingThrow(oneArgLambda); } // =================================================================================== // DBFlute Extension // ================= /** * Handle the entity in the optional object or exception if not present. *
     * memberBhv.selectEntity(cb -> {
     *     cb.setupSelect_MemberStatus();
     *     cb.query().setMemberId_Equal(1);
     * }).alwaysPresent(member -> { // called if value exists, or exception
     *     ... = member.getMemberName();
     *     member.getMemberStatus().alwaysPresent(status -> { // also relation
     *         ... = status.getMemberStatusName();
     *     });
     * });
     * 
* @param entityLambda The callback interface to consume the optional value. (NotNull) * @throws EntityAlreadyDeletedException When the entity instance wrapped in this optional object is null, which means entity has already been deleted (point is not found). */ public void alwaysPresent(OptionalThingConsumer entityLambda) { assertEntityLambdaNotNull(entityLambda); callbackAlwaysPresent(entityLambda); } /** * Get the entity instance or null if not present.
* basically use ifPresent() if might be not present, this is for emergency * @return The object instance wrapped in this optional object or null. (NullAllowed: if not present) * @deprecated basically use ifPresent() or use orElse(null) */ public ENTITY orElseNull() { return directlyGetOrElse(null); } // =================================================================================== // Assert Helper // ============= protected void assertEntityLambdaNotNull(Object entityLambda) { if (entityLambda == null) { throw new IllegalArgumentException("The argument 'entityLambda' should not be null."); } } }