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.commons.settings; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020import static org.apache.juneau.commons.utils.ThrowableUtils.*; 021 022import java.io.*; 023import java.net.*; 024import java.nio.charset.*; 025import java.nio.file.*; 026import java.util.*; 027import java.util.function.*; 028 029/** 030 * A specialized {@link Setting} for string values that provides convenience methods for type conversion. 031 * 032 * <p> 033 * This class extends {@link Setting} with type-specific conversion methods such as {@link #asInteger()}, 034 * {@link #asBoolean()}, {@link #asCharset()}, etc. 035 */ 036@SuppressWarnings({ 037 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 038}) 039public class StringSetting extends Setting<String> { 040 041 /** 042 * Creates a new StringSetting from a Settings instance and a Supplier. 043 * 044 * @param settings The Settings instance that created this setting. Must not be <jk>null</jk>. 045 * @param supplier The supplier that provides the string value. Must not be <jk>null</jk>. 046 */ 047 public StringSetting(Settings settings, Supplier<String> supplier) { 048 super(settings, supplier); 049 } 050 051 /** 052 * If a value is present, applies the provided mapping function to it and returns a StringSetting describing the result. 053 * 054 * <p> 055 * This method is specifically for String-to-String mappings. For mappings to other types, use the inherited {@link #map(Function)} method. 056 * 057 * <p> 058 * The returned StringSetting maintains its own cache, independent of this supplier. 059 * Resetting the mapped supplier does not affect this supplier, and vice versa. 060 * 061 * @param mapper A mapping function to apply to the value, if present. Must not be <jk>null</jk>. 062 * @return A StringSetting describing the result of applying a mapping function to the value of this StringSetting, if a value is present, otherwise an empty StringSetting. 063 */ 064 public StringSetting mapString(UnaryOperator<String> mapper) { 065 reqnn("mapper", mapper); 066 return new StringSetting(getSettings(), () -> { 067 String value = get(); 068 return nn(value) ? mapper.apply(value) : null; 069 }); 070 } 071 072 /** 073 * If a value is present, and the value matches the given predicate, returns a StringSetting describing the value, otherwise returns an empty StringSetting. 074 * 075 * <p> 076 * The returned StringSetting maintains its own cache, independent of this supplier. 077 * Resetting the filtered supplier does not affect this supplier, and vice versa. 078 * 079 * @param predicate A predicate to apply to the value, if present. Must not be <jk>null</jk>. 080 * @return A StringSetting describing the value of this StringSetting if a value is present and the value matches the given predicate, otherwise an empty StringSetting. 081 */ 082 @Override 083 public StringSetting filter(Predicate<? super String> predicate) { 084 reqnn("predicate", predicate); 085 return new StringSetting(getSettings(), () -> { 086 String value = get(); 087 return (nn(value) && predicate.test(value)) ? value : null; 088 }); 089 } 090 091 /** 092 * Converts the string value to an Integer. 093 * 094 * <p> 095 * The property value is parsed using {@link Integer#valueOf(String)}. If the property is not found 096 * or cannot be parsed as an integer, returns {@link Optional#empty()}. 097 * 098 * @return The property value as an Integer, or {@link Optional#empty()} if not found or not a valid integer. 099 */ 100 public Setting<Integer> asInteger() { 101 return map(v -> safeOrNull(() -> Integer.valueOf(v))).filter(Objects::nonNull); 102 } 103 104 /** 105 * Converts the string value to a Long. 106 * 107 * <p> 108 * The property value is parsed using {@link Long#valueOf(String)}. If the property is not found 109 * or cannot be parsed as a long, returns {@link Optional#empty()}. 110 * 111 * @return The property value as a Long, or {@link Optional#empty()} if not found or not a valid long. 112 */ 113 public Setting<Long> asLong() { 114 return map(v -> safeOrNull(() -> Long.valueOf(v))).filter(Objects::nonNull); 115 } 116 117 /** 118 * Converts the string value to a Boolean. 119 * 120 * <p> 121 * The property value is parsed using {@link Boolean#parseBoolean(String)}, which returns <c>true</c> 122 * if the value is (case-insensitive) "true", otherwise <c>false</c>. Note that this method will 123 * return <c>Optional.of(false)</c> for any non-empty value that is not "true", and 124 * {@link Optional#empty()} only if the property is not set. 125 * 126 * @return The property value as a Boolean, or {@link Optional#empty()} if not found. 127 */ 128 public Setting<Boolean> asBoolean() { 129 return map(Boolean::parseBoolean); 130 } 131 132 /** 133 * Converts the string value to a Double. 134 * 135 * <p> 136 * The property value is parsed using {@link Double#valueOf(String)}. If the property is not found 137 * or cannot be parsed as a double, returns {@link Optional#empty()}. 138 * 139 * @return The property value as a Double, or {@link Optional#empty()} if not found or not a valid double. 140 */ 141 public Setting<Double> asDouble() { 142 return map(v -> safeOrNull(() -> Double.valueOf(v))).filter(Objects::nonNull); 143 } 144 145 /** 146 * Converts the string value to a Float. 147 * 148 * <p> 149 * The property value is parsed using {@link Float#valueOf(String)}. If the property is not found 150 * or cannot be parsed as a float, returns {@link Optional#empty()}. 151 * 152 * @return The property value as a Float, or {@link Optional#empty()} if not found or not a valid float. 153 */ 154 public Setting<Float> asFloat() { 155 return map(v -> safeOrNull(() -> Float.valueOf(v))).filter(Objects::nonNull); 156 } 157 158 /** 159 * Converts the string value to a File. 160 * 161 * <p> 162 * The property value is converted to a {@link File} using the {@link File#File(String)} constructor. 163 * If the property is not found, returns {@link Optional#empty()}. Note that this method does not 164 * validate that the file path is valid or that the file exists. 165 * 166 * @return The property value as a File, or {@link Optional#empty()} if not found. 167 */ 168 public Setting<File> asFile() { 169 return map(File::new); 170 } 171 172 /** 173 * Converts the string value to a Path. 174 * 175 * <p> 176 * The property value is converted to a {@link Path} using {@link Paths#get(String, String...)}. 177 * If the property is not found or the path string is invalid, returns {@link Optional#empty()}. 178 * 179 * @return The property value as a Path, or {@link Optional#empty()} if not found or not a valid path. 180 */ 181 public Setting<Path> asPath() { 182 return map(v -> safeOrNull(() -> Paths.get(v))).filter(Objects::nonNull); 183 } 184 185 /** 186 * Converts the string value to a URI. 187 * 188 * <p> 189 * The property value is converted to a {@link URI} using {@link URI#create(String)}. 190 * If the property is not found or the URI string is invalid, returns {@link Optional#empty()}. 191 * 192 * @return The property value as a URI, or {@link Optional#empty()} if not found or not a valid URI. 193 */ 194 public Setting<URI> asURI() { 195 return map(v -> safeOrNull(() -> URI.create(v))).filter(Objects::nonNull); 196 } 197 198 /** 199 * Converts the string value to a Charset. 200 * 201 * <p> 202 * The property value is converted to a {@link Charset} using {@link Charset#forName(String)}. 203 * If the property is not found or the charset name is not supported, returns {@link Optional#empty()}. 204 * 205 * @return The property value as a Charset, or {@link Optional#empty()} if not found or not a valid charset. 206 */ 207 public Setting<Charset> asCharset() { 208 return map(v -> safeOrNull(() -> Charset.forName(v))).filter(Objects::nonNull); 209 } 210 211 /** 212 * Converts the string value to the specified type using the Settings type conversion functions. 213 * 214 * <p> 215 * The property value is converted using {@link Settings#toType(String, Class)}. If the property is not found 216 * or cannot be converted to the specified type, returns {@link Optional#empty()}. 217 * 218 * @param <T> The target type. 219 * @param c The target class. Must not be <jk>null</jk>. 220 * @return The property value as the specified type, or {@link Optional#empty()} if not found or not a valid conversion. 221 */ 222 public <T> Setting<T> asType(Class<T> c) { 223 reqnn("c", c); 224 return map(v -> getSettings().toType(v, c)).filter(Objects::nonNull); 225 } 226}