Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
builders.dsl.spreadsheet.parser.data.DataSpreadsheetParser Maven / Gradle / Ivy
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Vladimir Orany.
*
* 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
*
* https://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 builders.dsl.spreadsheet.parser.data;
import builders.dsl.spreadsheet.api.BorderStyle;
import builders.dsl.spreadsheet.api.Color;
import builders.dsl.spreadsheet.api.FontStyle;
import builders.dsl.spreadsheet.api.ForegroundFill;
import builders.dsl.spreadsheet.api.Keywords;
import builders.dsl.spreadsheet.builder.api.BorderDefinition;
import builders.dsl.spreadsheet.builder.api.CellDefinition;
import builders.dsl.spreadsheet.builder.api.CellStyleDefinition;
import builders.dsl.spreadsheet.builder.api.CommentDefinition;
import builders.dsl.spreadsheet.builder.api.DimensionModifier;
import builders.dsl.spreadsheet.builder.api.FontDefinition;
import builders.dsl.spreadsheet.builder.api.HasStyle;
import builders.dsl.spreadsheet.builder.api.ImageCreator;
import builders.dsl.spreadsheet.builder.api.PageDefinition;
import builders.dsl.spreadsheet.builder.api.RowDefinition;
import builders.dsl.spreadsheet.builder.api.SheetDefinition;
import builders.dsl.spreadsheet.builder.api.SpreadsheetBuilder;
import builders.dsl.spreadsheet.builder.api.WorkbookDefinition;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// TODO: apply "stylesheet" from list of styles
public class DataSpreadsheetParser {
private static final List REQUIRES_NAME = Collections.singletonList("name");
private static final Pattern DIMENSION_IN_POINTS = Pattern.compile("(\\d+)\\s?(p(oin)?ts?)?");
private static final Pattern DIMENSION_IN_CM = Pattern.compile("(\\d+)\\s?cm");
private static final Pattern DIMENSION_IN_INCHES = Pattern.compile("(\\d+)\\s?in(ch(es)?)?");
private static final Pattern ISO_DATE_PATTERN = Pattern.compile("^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d{1,9})?(?:Z|[+-][01]\\d:[0-5]\\d)$");
private final SpreadsheetBuilder builder;
public DataSpreadsheetParser(SpreadsheetBuilder builder) {
this.builder = builder;
}
private static void doSafe(String entryPath, T value, Consumer operation) {
try {
operation.accept(value);
} catch (InvalidPropertyException e){
// if alredy IPE, just rethrow
throw e;
} catch (Exception e) {
// wrap any other exception to IPE
throw new InvalidPropertyException(e, entryPath, value);
}
}
private void handleNumber(String path, Object value, Consumer consumer) {
if (value instanceof Number) {
consumer.accept((Number) value);
return;
}
throw new InvalidPropertyException("Value must be number", path, value);
}
private void handleBoolean(String path, Object value, Consumer consumer) {
if (value instanceof Boolean) {
consumer.accept((Boolean) value);
return;
}
throw new InvalidPropertyException("Value must be boolean", path, value);
}
private void ifTrue(String path, Object value, Runnable runnable) {
handleBoolean(path, value, bool -> {
if (bool) {
runnable.run();
}
});
}
private static void eachItemWithIndex(Object value, String path, BiConsumer consumer) {
if (!(value instanceof Iterable)) {
throw new InvalidPropertyException("Value must be iterable!", path, value);
}
Iterable> iterable = (Iterable>) value;
int index = 0;
for (Object item : iterable) {
consumer.accept(item, index++);
}
}
private static void eachItemWithPath(Object value, String path, BiConsumer consumer) {
eachItemWithIndex(value, path, (item, index) -> {
final String itemPath = path + "[" + index + "]";
consumer.accept(item, itemPath);
});
}
private static void withMap(Object value, String path, Consumer> consumer) {
withMap(value, path, Collections.emptyList(), consumer);
}
private static void withMap(Object value, String path, Iterable requiredProperties, Consumer> consumer) {
withMap(value, path, requiredProperties, (map, localPath) -> consumer.accept(map));
}
private static void withMap(Object value, String path, Iterable requiredProperties, BiConsumer, String> consumer) {
if (!(value instanceof Map)) {
throw new InvalidPropertyException("Definition must be map", path, value);
}
Map, ?> map = (Map, ?>) value;
for (String requiredProperty: requiredProperties) {
if (!map.containsKey(requiredProperty)) {
throw new InvalidPropertyException("Definition is missing '" + requiredProperty + "' property", path, value);
}
}
doSafe(path, map, v -> consumer.accept(checkedMap(v), path));
}
private static void handleMap(String path, Map map, MapEntryHandler handler) {
for (Map.Entry entry : map.entrySet()) {
String entryPath = path + "." + entry.getKey();
doSafe(entryPath, entry.getValue(), value -> handler.handle(entryPath, entry.getKey(), entry.getValue()));
}
}
@SuppressWarnings({
"unchecked",
"rawtypes"
})
private static Map checkedMap(Map map) {
return Collections.checkedMap(map, String.class, Object.class);
}
private static void eachItemAsMap(Object value, String path, Iterable requiredProperties, BiConsumer, String> consumer) {
eachItemWithPath(value, path, (item, itemPath) -> withMap(item, itemPath, requiredProperties, map -> consumer.accept(map, itemPath)));
}
public void build(Iterable> value) {
build(Collections.singletonMap("sheets", value));
}
public void build(final Map definitionMap) {
this.builder.build(w -> handleWorkbook(w, definitionMap));
}
@SuppressWarnings("unchecked")
public void build(Object value) {
if (value == null) {
throw new InvalidPropertyException("No Data", "", null);
}
if (value instanceof Map) {
build((Map) value);
} else if (value instanceof Iterable) {
build((Iterable>) value);
} else {
throw new InvalidPropertyException("Unsupported definition type (" + value.getClass() + "): ", "", value);
}
}
private void handleWorkbook(WorkbookDefinition w, Map definitionMap) {
for (Map.Entry entry : definitionMap.entrySet()) {
switch (entry.getKey()) {
case "styles":
eachItemAsMap(entry.getValue(), entry.getKey(), REQUIRES_NAME, (map, localPath) -> w.style(String.valueOf(map.get("name")), s -> handleStyle(s, localPath, map)));
break;
case "sheets":
eachItemWithPath(entry.getValue(), entry.getKey(), (item, itemPath) -> {
if (item instanceof Map) {
withMap(item, itemPath, REQUIRES_NAME, sheet -> handleSheet(w, itemPath, sheet));
} else {
Map sheet = new HashMap<>();
sheet.put("rows", item);
sheet.put("name", "Sheet1");
handleSheet(w, itemPath, sheet);
}
});
break;
default:
throw new InvalidPropertyException("Unknown property: " + entry.getKey(), entry.getKey(), entry.getValue());
}
}
}
private void handleSheet(WorkbookDefinition w, String localPath, Map map) {
w.sheet(String.valueOf(map.get("name")), s -> handleSheet(s, localPath, map));
}
private void handleSheet(SheetDefinition s, String path, Map map) {
handleMap(path, map, (String entryPath, String key, Object value) -> {
switch (key) {
case "rows":
handleRows(s, path, value);
break;
case "filter":
ifTrue(entryPath, value, () -> s.filter(Keywords.Auto.AUTO));
break;
case "freeze":
handleFreeze(s, entryPath, value);
break;
case "page":
withMap(value, entryPath, page -> s.page(p -> handlePage(p, entryPath, page)));
break;
case "password":
s.password(String.valueOf(value));
break;
case "state":
handleState(s, value);
break;
case "name":
// handled already
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleState(SheetDefinition s, Object value) {
s.state(Keywords.SheetState.valueOf(asEnumName(value)));
}
private void handleRows(SheetDefinition s, String path, Object value) {
eachItemWithPath(value, path, (item, itemPath) -> {
if (item instanceof Map) {
withMap(item, itemPath, Collections.emptyList(), row -> handleRow(s, itemPath, row));
} else if (item instanceof Iterable) {
handleRow(s, itemPath, Collections.singletonMap("cells", item));
}
});
}
private void handlePage(PageDefinition p, String path, Map page) {
handleMap(path, page, (String entryPath, String key, Object value) -> {
switch (key) {
case "fit":
withMap(value, entryPath, fit -> handlePageFit(p, entryPath, fit));
break;
case "orientation":
handlePageOrientation(p, value);
break;
case "paper":
handlePagePaper(p, value);
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handlePagePaper(PageDefinition p, Object value) {
p.paper(Keywords.Paper.valueOf(asEnumName(value)));
}
private void handlePageOrientation(PageDefinition p, Object value) {
p.orientation(Keywords.Orientation.valueOf(asEnumName(value)));
}
private void handlePageFit(PageDefinition p, String path, Map fit) {
handleMap(path, fit, (entryPath, key, value) -> {
switch (key) {
case "width":
handleNumber(entryPath, value, number -> p.fit(Keywords.Fit.WIDTH).to(number.intValue()));
break;
case "height":
handleNumber(entryPath, value, number -> p.fit(Keywords.Fit.HEIGHT).to(number.intValue()));
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleFreeze(SheetDefinition s, String path, Object freeze) {
AtomicInteger row = new AtomicInteger(0);
AtomicInteger column = new AtomicInteger(0);
AtomicReference columnAsString = new AtomicReference<>();
withMap(freeze, path, map -> handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "row":
handleNumber(entryPath, value, number -> row.set(number.intValue()));
break;
case "column":
if (value instanceof Number) {
handleNumber(entryPath, value, number -> column.set(number.intValue()));
} else {
columnAsString.set(String.valueOf(value));
}
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
}));
if (columnAsString.get() != null) {
s.freeze(columnAsString.get(), row.get());
} else {
s.freeze(column.get(), row.get());
}
}
private void handleRow(SheetDefinition s, String path, Map row) {
if (row.containsKey("group") && row.size() == 1) {
s.group(group -> eachItemAsMap(row.get("group"), path + "." + "group", Collections.emptyList(), (item, itemPath) -> handleRow(group, itemPath, item)));
} else if (row.containsKey("collapse") && row.size() == 1) {
s.collapse(collapse -> eachItemAsMap(row.get("collapse"), path + "." + "collapse", Collections.emptyList(), (item, itemPath) -> handleRow(collapse, itemPath, item)));
} else if (row.containsKey("number")) {
handleNumber(path, row.get("number"), number -> s.row(number.intValue(), r -> handleRow(r, path, row)));
} else {
s.row(r -> handleRow(r, path, row));
}
}
private void handleRow(RowDefinition r, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "styles":
handleStyles(r, entryPath, value);
break;
case "cells":
eachItemWithPath(value, entryPath, (item, itemPath) -> handleCell(r, itemPath, item));
break;
case "number":
// already handled
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleCell(RowDefinition r, String itemPath, Object item) {
if (item instanceof Map) {
withMap(item, itemPath, map -> handleCellFromMap(r, itemPath, map));
} else {
r.cell(c -> handleCellValue(c, item));
}
}
private void handleCellFromMap(RowDefinition r, String path, Map map) {
if (map.containsKey("group") && map.size() == 1) {
r.group(group -> eachItemWithPath(map.get("group"), path + "." + "group", (item, itemPath) -> handleCell(group, itemPath, item)));
} else if (map.containsKey("collapse") && map.size() == 1) {
r.collapse(collapse -> eachItemWithPath(map.get("collapse"), path + "." + "collapse", (item, itemPath) -> handleCell(collapse, itemPath, item)));
} else if (map.containsKey("column")) {
Object column = map.get("column");
if (column instanceof Number) {
handleNumber(path, column, number -> r.cell(number.intValue(), c -> handleCell(c, path, map)));
} else {
r.cell(String.valueOf(column), c -> handleCell(c, path, map));
}
} else {
r.cell(c -> handleCell(c, path, map));
}
}
private void handleCell(CellDefinition c, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "value":
handleCellValue(c, value);
break;
case "name":
handleCellName(c, value);
break;
case "formula":
handleCellFormula(c, value);
break;
case "comment":
handleCellComment(c, entryPath, value);
break;
case "link":
handleCellLink(c, entryPath, value);
break;
case "colspan":
handleCellColspan(c, entryPath, value);
break;
case "rowspan":
handleCellRowspan(c, entryPath, value);
break;
case "width":
handleCellWidth(c, entryPath, value);
break;
case "height":
handleCellHeight(c, entryPath, value);
break;
case "text":
handleCellText(c, entryPath, value);
break;
case "styles":
handleStyles(c, entryPath, value);
break;
case "image":
handleCellImage(c, entryPath, value);
break;
case "column":
// already handled
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleCellText(CellDefinition c, String entryPath, Object value) {
if (value instanceof Iterable) {
eachItemWithPath(value, entryPath, (item, itemPath) -> {
if (item instanceof Map) {
withMap(item, itemPath, Collections.singletonList("content"), map -> {
Object font = map.get("font");
String content = String.valueOf(map.get("content"));
if (font == null) {
c.text(content);
} else {
String fontPath = itemPath + "." + "font";
withMap(font, fontPath, fontMap -> c.text(content, f -> handleFont(f, fontPath, fontMap)));
}
});
} else {
c.text(String.valueOf(item));
}
});
} else {
c.value(value);
}
}
private void handleCellImage(CellDefinition c, String path, Object image) {
Map> imageCreators = new LinkedHashMap<>();
imageCreators.put("png", c::png);
imageCreators.put("jpeg", c::jpeg);
imageCreators.put("jpg", c::jpeg);
imageCreators.put("pict", c::pict);
imageCreators.put("emf", c::emf);
imageCreators.put("wmf", c::wmf);
imageCreators.put("dib", c::dib);
if (image instanceof Map) {
withMap(image, path, Arrays.asList("url", "type"), map -> {
String type = String.valueOf(map.get("type")).toLowerCase();
String url = String.valueOf(map.get("url"));
if (!imageCreators.containsKey(type)) {
throw new InvalidPropertyException("Unknown image type", path + "." + "type", type);
}
try {
new URL(url);
} catch (MalformedURLException e) {
throw new InvalidPropertyException("Malformed image URL", path + "." + "url", url);
}
imageCreators.get(type).apply(Keywords.Image.IMAGE).from(url);
});
return;
}
String url = String.valueOf(image);
try {
new URL(url);
} catch (MalformedURLException e) {
throw new InvalidPropertyException("Malformed image URL", path, url);
}
String lowerCase = url.toLowerCase();
boolean linkCreated = false;
for (String extension: imageCreators.keySet()) {
if (lowerCase.endsWith(extension)) {
imageCreators.get(extension).apply(Keywords.Image.IMAGE).from(url);
linkCreated = true;
break;
}
}
if (!linkCreated) {
throw new InvalidPropertyException("Could not determine image type. Please be sure that the URL ends with one of following extensions: " + String.join(",", imageCreators.keySet()), path, url);
}
}
private void handleCellLink(CellDefinition c, String path, Object value) {
String link = String.valueOf(value);
try {
URI uri = new URI(link);
if ("http".equals(uri.getScheme()) || ("https".equals(uri.getScheme()))) {
c.link(Keywords.To.TO).url(link);
} else if ("mailto".equals(uri.getScheme())) {
c.link(Keywords.To.TO).email(link.substring(7));
} else if ("file".equals(uri.getScheme())) {
c.link(Keywords.To.TO).file(link.substring(5));
} else {
c.link(Keywords.To.TO).name(link);
}
} catch (URISyntaxException e) {
throw new InvalidPropertyException("Invalid link format", e, path, value);
}
}
private void handleCellComment(CellDefinition c, String entryPath, Object value) {
if (value instanceof String) {
c.comment((String) value);
} else {
c.comment(comment -> withMap(value, entryPath, map -> handleCellComment(comment, entryPath, map)));
}
}
private void handleCellComment(CommentDefinition c, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "author":
c.author(String.valueOf(value));
break;
case "text":
c.text(String.valueOf(value));
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleCellWidth(CellDefinition c, String path, Object value) {
if ("auto".equals(value)) {
c.width(Keywords.Auto.AUTO);
} else {
handleDimension(value, path, c::width);
}
}
private void handleDimension(Object value, String path, Function dimensionSetter) {
if (value instanceof Number) {
dimensionSetter.apply(((Number) value).doubleValue());
} else {
String dimension = String.valueOf(value);
Matcher cmMatcher = DIMENSION_IN_CM.matcher(dimension);
Matcher inchMatcher = DIMENSION_IN_INCHES.matcher(dimension);
Matcher pointMatcher = DIMENSION_IN_POINTS.matcher(dimension);
if (cmMatcher.matches()) {
dimensionSetter.apply(Double.valueOf(cmMatcher.group(1))).cm();
} else if (inchMatcher.matches()) {
dimensionSetter.apply(Double.valueOf(inchMatcher.group(1))).inch();
} else if (pointMatcher.matches()) {
dimensionSetter.apply(Double.valueOf(pointMatcher.group(1)));
} else {
throw new InvalidPropertyException("Invalid dimension format", path, value);
}
}
}
private void handleCellHeight(CellDefinition c, String path, Object value) {
handleDimension(value, path, c::height);
}
private void handleCellColspan(CellDefinition c, String path, Object value) {
handleNumber(path, value, number -> c.colspan(number.intValue()));
}
private void handleCellRowspan(CellDefinition c, String path, Object value) {
handleNumber(path, value, number -> c.rowspan(number.intValue()));
}
private void handleCellFormula(CellDefinition c, Object value) {
c.formula(String.valueOf(value));
}
private void handleCellName(CellDefinition c, Object value) {
c.name(String.valueOf(value));
}
private void handleCellValue(CellDefinition c, Object value) {
if (value instanceof String && ISO_DATE_PATTERN.matcher((String)value).matches()) {
c.value(Date.from(ZonedDateTime.parse((String)value, DateTimeFormatter.ISO_DATE_TIME).toInstant()));
return;
}
c.value(value);
}
private void handleStyles(HasStyle r, String path, Object value) {
List styles = new ArrayList<>();
List> stylesDefinitions = new ArrayList<>();
eachItemWithPath(value, path, (item, itemPath) -> {
if (item instanceof String) {
styles.add((String) item);
} else {
withMap(item, itemPath, map -> stylesDefinitions.add(style -> handleStyle(style, itemPath, map)));
}
});
r.styles(styles, stylesDefinitions);
}
private void handleFont(FontDefinition f, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "color":
handleFontColor(entryPath, f, value);
break;
case "size":
handleFontSize(f, entryPath, value);
break;
case "style":
handleFontStyle(f, value);
break;
case "styles":
eachItemWithPath(value, entryPath, (item, itemPath) -> handleFontStyle(f, item));
break;
case "name":
handleFontName(f, value);
break;
case "content":
// from text - ignore
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleFontStyle(FontDefinition f, Object value) {
f.style(FontStyle.valueOf(asEnumName(value)));
}
private void handleFontName(FontDefinition f, Object value) {
f.name(String.valueOf(value));
}
private void handleFontSize(FontDefinition f, String path, Object value) {
handleNumber(path, value, number -> f.size(number.intValue()));
}
private void handleFontColor(String path, FontDefinition f, Object value) {
handleColor(path, value, f::color, f::color);
}
private void handleColor(String path, Object value, Consumer hexColorConsumer, Consumer colorConsumer) {
String color = String.valueOf(value);
if (color.startsWith("#")) {
hexColorConsumer.accept(color);
} else {
colorConsumer.accept(readFakeEnumValue(path, color, Color.class, true));
}
}
private void handleBorder(BorderDefinition b, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "style":
handleBorderStyle(b, value);
break;
case "color":
handleBorderColor(entryPath, b, value);
break;
case "side":
// already handled
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleBorderColor(String path, BorderDefinition b, Object value) {
handleColor(path, value, b::color, b::color);
}
private void handleBorderStyle(BorderDefinition b, Object value) {
b.style(BorderStyle.valueOf(asEnumName(value)));
}
private void handleBorder(CellStyleDefinition s, String path, Map map) {
String key = "side";
if (!map.containsKey(key)) {
s.border(b -> handleBorder(b, path, map));
return;
}
List sides = new ArrayList<>();
Object value = map.get(key);
if (!(value instanceof Iterable)) {
value = Collections.singletonList(value);
}
eachItemWithIndex(value, path + "." + key, (item, index) -> sides.add(readFakeEnumValue(path + "." + key + "[" + index + "]", item, Keywords.BorderSide.class)));
if (sides.size() == 4 || sides.isEmpty()) {
s.border(b -> handleBorder(b, path, map));
} else if (sides.size() == 3) {
s.border(sides.get(0), sides.get(1), sides.get(2), b -> handleBorder(b, path, map));
} else if (sides.size() == 2) {
s.border(sides.get(0), sides.get(1), b -> handleBorder(b, path, map));
} else if (sides.size() == 1) {
s.border(sides.get(0), b -> handleBorder(b, path, map));
}
}
private void handleStyle(CellStyleDefinition s, String path, Map map) {
handleMap(path, map, (entryPath, key, value) -> {
switch (key) {
case "align":
handleAlign(s, entryPath, value);
break;
case "background":
handleBackground(entryPath, s, value);
break;
case "base":
handleBase(s, value);
break;
case "borders":
eachItemAsMap(value, entryPath, Collections.emptyList(), (border, localPath) -> handleBorder(s, localPath, border));
break;
case "fill":
handleFill(s, value);
break;
case "font":
withMap(value, entryPath, Collections.emptyList(), (font, localPath) -> s.font(f -> handleFont(f, localPath, font)));
break;
case "foreground":
handleForeground(entryPath, s, value);
break;
case "format":
handleFormat(s, value);
break;
case "indent":
handleIndent(s, entryPath, value);
break;
case "rotation":
handleRotation(s, entryPath, value);
break;
case "wrap":
handleWrap(s, entryPath, value);
break;
case "name":
// handled already
break;
default:
throw new InvalidPropertyException("Unknown property: " + key, path, value);
}
});
}
private void handleWrap(CellStyleDefinition s, String entryPath, Object value) {
ifTrue(entryPath, value, () -> s.wrap(Keywords.Text.WRAP));
}
private void handleFill(CellStyleDefinition s, Object value) {
s.fill(ForegroundFill.valueOf(asEnumName(value)));
}
private void handleBase(CellStyleDefinition s, Object value) {
s.base(String.valueOf(value));
}
private void handleBackground(String path, CellStyleDefinition s, Object value) {
handleColor(path, value, s::background, s::background);
}
private void handleForeground(String path, CellStyleDefinition s, Object value) {
handleColor(path, value, s::foreground, s::foreground);
}
private void handleFormat(CellStyleDefinition s, Object value) {
s.format(String.valueOf(value));
}
private void handleIndent(CellStyleDefinition s, String path, Object value) {
handleNumber(path, value, number -> s.indent(number.intValue()));
}
private void handleRotation(CellStyleDefinition s, String path, Object value) {
handleNumber(path, value, number -> s.rotation(number.intValue()));
}
private void handleAlign(CellStyleDefinition s, String path, Object value) {
withMap(value, path, map -> s.align(
readFakeEnumValue(path, map, "vertical", Keywords.VerticalAlignment.class),
readFakeEnumValue(path, map, "horizontal", Keywords.HorizontalAlignment.class)
));
}
private T readFakeEnumValue(String path, Map map, String key, Class type) {
if (map.containsKey(key)) {
return readFakeEnumValue(path + '.' + key, map.get(key), type);
}
return null;
}
private T readFakeEnumValue(String path, Object value, Class type) {
return readFakeEnumValue(path, value, type, false);
}
private T readFakeEnumValue(String path, Object value, Class type, boolean keepCase) {
try {
return type.cast(type.getField(keepCase ? String.valueOf(value) : asEnumName(value)).get(null));
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new InvalidPropertyException(type.getSimpleName() + " " + value + " does not exist", e, path, value);
}
}
private String asEnumName(Object value) {
if (String.valueOf(value).matches("^[A-Z_]+$")) {
return String.valueOf(value);
}
return String.valueOf(value).replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase();
}
@FunctionalInterface private interface MapEntryHandler {
void handle(String entryPath, String key, Object value);
}
}