001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau; 018 019import java.util.*; 020 021import org.apache.juneau.common.utils.*; 022import org.apache.juneau.cp.*; 023import org.apache.juneau.internal.*; 024 025/** 026 * Base class for bean builders. 027 * 028 * <h5 class='section'>See Also:</h5><ul> 029 * </ul> 030 * 031 * @param <T> The bean type that the builder creates. 032 */ 033public class BeanBuilder<T> { 034 035 private Class<? extends T> type, defaultType; 036 private T impl; 037 private final BeanStore beanStore; 038 039 /** 040 * Constructor. 041 * 042 * @param beanStore The bean store to use for creating beans. 043 * @param defaultType The default bean type that this builder creates. 044 */ 045 protected BeanBuilder(Class<? extends T> defaultType, BeanStore beanStore) { 046 this.defaultType = type = defaultType; 047 this.beanStore = beanStore; 048 } 049 050 /** 051 * Constructor. 052 * 053 * @param defaultType The type of bean being created. 054 */ 055 protected BeanBuilder(Class<? extends T> defaultType) { 056 this(defaultType, BeanStore.INSTANCE); 057 } 058 059 /** 060 * Copy constructor. 061 * 062 * @param copyFrom The bean store to copy from. 063 */ 064 protected BeanBuilder(BeanBuilder<T> copyFrom) { 065 type = copyFrom.type; 066 impl = copyFrom.impl; 067 beanStore = copyFrom.beanStore; 068 } 069 070 /** 071 * Creates the bean. 072 * 073 * @return A new bean. 074 */ 075 public T build() { 076 if (impl != null) 077 return impl; 078 if (type == null || type == defaultType) 079 return buildDefault(); 080 return creator().run(); 081 } 082 083 /** 084 * Instantiates the creator for this bean. 085 * 086 * <p> 087 * Subclasses can override this to provide specialized handling. 088 * 089 * @return The creator for this bean. 090 */ 091 protected BeanCreator<? extends T> creator() { 092 return beanStore 093 .createBean(type().orElseThrow(() -> new IllegalStateException("Type not specified."))) 094 .builder(BeanBuilder.class, this); 095 } 096 097 /** 098 * Creates the bean when the bean type is <jk>null</jk> or is the default value. 099 * 100 * @return A new bean. 101 */ 102 protected T buildDefault() { 103 return beanStore 104 .createBean(type().orElseThrow(() -> new IllegalStateException("Type not specified."))) 105 .builder(BeanBuilder.class, this) 106 .run(); 107 } 108 109 /** 110 * Overrides the bean type produced by the {@link #build()} method. 111 * 112 * <p> 113 * Use this method if you want to instantiated a bean subclass. 114 * 115 * @param value The setting value. 116 * @return This object. 117 */ 118 @SuppressWarnings("unchecked") 119 public BeanBuilder<T> type(Class<?> value) { 120 type = (Class<T>)value; 121 return this; 122 } 123 124 /** 125 * Returns the implementation type specified via {@link #type(Class)}. 126 * 127 * @return The implementation type specified via {@link #type(Class)}. 128 */ 129 protected Optional<Class<? extends T>> type() { 130 return Utils.opt(type); 131 } 132 133 /** 134 * Overrides the bean returned by the {@link #build()} method. 135 * 136 * <p> 137 * Use this method if you want this builder to return an already-instantiated bean. 138 * 139 * @param value The setting value. 140 * @return This object. 141 */ 142 @SuppressWarnings("unchecked") 143 public BeanBuilder<T> impl(Object value) { 144 this.impl = (T)value; 145 return this; 146 } 147 148 /** 149 * Returns the override bean specified via {@link #impl(Object)}. 150 * 151 * @return The override bean specified via {@link #impl(Object)}. 152 */ 153 protected Optional<T> impl() { 154 return Utils.opt(impl); 155 } 156 157 /** 158 * Returns the bean store passed in through the constructor. 159 * 160 * @return The bean store passed in through the constructor. 161 */ 162 public BeanStore beanStore() { 163 return beanStore; 164 } 165}