001/* 002 * Copyright 2023 the original author or authors. 003 * <p> 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 * <p> 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * <p> 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 */ 016package de.cuioss.tools.formatting; 017 018import static de.cuioss.tools.collect.MoreCollections.isEmpty; 019import static de.cuioss.tools.string.MoreStrings.emptyToNull; 020 021import java.io.Serializable; 022import java.util.ArrayList; 023import java.util.List; 024 025import lombok.Data; 026import lombok.EqualsAndHashCode; 027import lombok.NonNull; 028import lombok.ToString; 029 030/** 031 * Provide concatenation of strings by using 032 * {@linkplain String#join(CharSequence, CharSequence...)}. Furthermore, 033 * formatter supports different strategies for values handling. (see 034 * {@link ValueHandling}) 035 * 036 * @author Eugen Fischer 037 */ 038@Data 039public class SimpleFormatter implements Serializable { 040 041 /** 042 * 043 */ 044 public enum ValueHandling { 045 /** 046 * Format all available data. If some are null or empty skip them silently. 047 */ 048 FORMAT_IF_ANY_AVAILABLE, 049 /** 050 * Format all available data. If one of them is null or empty skip all silently. 051 */ 052 FORMAT_IF_ALL_AVAILABLE 053 } 054 055 /** 056 * serial version UID 057 */ 058 private static final long serialVersionUID = -4761082365099064435L; 059 060 private final String separator; 061 062 private final ValueHandling handling; 063 064 /** 065 * Concatenate values by separator and return result inside the parentheses. 066 * Handle parameter according defined ValueHandling strategy. 067 * 068 * @param values ellipses of string values 069 * 070 * @return {@code null} if nothing to put in parentheses 071 */ 072 public String formatParentheses(final String... values) { 073 return format(cleanUp(values)); 074 } 075 076 /** 077 * Concatenate values by separator according defined ValueHandling strategy. 078 * 079 * @param values ellipses of string values 080 * 081 * @return {@code null} if nothing to concatenate 082 */ 083 public String format(final String... values) { 084 return getJoined(cleanUp(values)); 085 } 086 087 private List<String> cleanUp(final String... values) { 088 final List<String> result = new ArrayList<>(0); 089 if (null != values) { 090 for (final String item : values) { 091 final var value = emptyToNull(item); 092 if (null == value) { 093 if (ValueHandling.FORMAT_IF_ALL_AVAILABLE.equals(handling)) { 094 result.clear(); 095 break; 096 } 097 } else { 098 result.add(value); 099 } 100 } 101 } 102 return result; 103 } 104 105 private String getJoined(final List<String> values) { 106 if (isEmpty(values)) { 107 return null; 108 } 109 var filtered = values.stream().filter(element -> !isEmpty(element)).toList(); 110 if (isEmpty(filtered)) { 111 return null; 112 } 113 return String.join(separator, filtered); 114 } 115 116 private String format(final List<String> values) { 117 final var joined = getJoined(values); 118 if (null != joined) { 119 return "(%s)".formatted(joined); 120 } 121 return null; 122 } 123 124 /** 125 * @return a newly created instance of {@link SimpleFormatterBuilder} 126 */ 127 public static SimpleFormatterBuilder builder() { 128 return new SimpleFormatterBuilder(); 129 } 130 131 /** 132 * Internal Builder representation 133 */ 134 @ToString 135 @EqualsAndHashCode 136 public static class SimpleFormatterBuilder implements Serializable { 137 138 private static final long serialVersionUID = 6414005370772800008L; 139 140 /** 141 * Use {@linkplain ValueHandling#FORMAT_IF_ALL_AVAILABLE} as value handling 142 * strategy 143 * 144 * @return initialized {@link BuilderWithStrategy} with defined value handling 145 * strategy 146 */ 147 public BuilderWithStrategy skipResultIfAnyValueIsMissing() { 148 return new BuilderWithStrategy(ValueHandling.FORMAT_IF_ALL_AVAILABLE); 149 } 150 151 /** 152 * Use {@linkplain ValueHandling#FORMAT_IF_ANY_AVAILABLE} as value handling 153 * strategy 154 * 155 * @return initialized {@link BuilderWithStrategy} with defined value handling 156 * strategy 157 */ 158 public BuilderWithStrategy ignoreMissingValues() { 159 return new BuilderWithStrategy(ValueHandling.FORMAT_IF_ANY_AVAILABLE); 160 } 161 162 /** 163 * Internal Builder representation incorporating a strategy 164 */ 165 @ToString 166 @EqualsAndHashCode 167 public static class BuilderWithStrategy implements Serializable { 168 169 private static final long serialVersionUID = -1987354973684803562L; 170 171 private final ValueHandling valueHandlingStrategy; 172 173 protected BuilderWithStrategy(final ValueHandling strategy) { 174 valueHandlingStrategy = strategy; 175 } 176 177 /** 178 * Create SimpleFormatter 179 * 180 * @param separator must not be null 181 * 182 * @return {@link SimpleFormatter} with defined value handling strategy and 183 * separator 184 */ 185 public SimpleFormatter separatesBy(@NonNull final String separator) { 186 return new SimpleFormatter(separator, valueHandlingStrategy); 187 } 188 } 189 190 } 191}