Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Consumer;
import org.apache.fesod.common.util.ListUtils;
import org.apache.fesod.sheet.converters.Converter;
import org.apache.fesod.sheet.enums.CacheLocationEnum;
Expand All @@ -40,8 +41,9 @@
*/
public abstract class AbstractParameterBuilder<T extends AbstractParameterBuilder, C extends BasicParameter> {
/**
* You can only choose one of the {@link #head(List)} and {@link #head(Class)}
* You can only choose one of the ({@link #head(List)} or {@link #head(Consumer)}) and {@link #head(Class)}
*
* @see #head(Consumer)
* @param head
* @return
*/
Expand All @@ -50,6 +52,18 @@ public T head(List<List<String>> head) {
return self();
}

/**
* You can only choose one of the ({@link #head(List)} or {@link #head(Consumer)}) and {@link #head(Class)}
*
* @see #head(List)
* @param headBuilderConsumer
* @return
*/
public T head(Consumer<HeadBuilder> headBuilderConsumer) {
parameter().setHead(DefaultHeadBuilder.define(headBuilderConsumer));
return self();
}

/**
* Ensures and returns a mutable head list.
*
Expand All @@ -68,7 +82,7 @@ private List<List<String>> toMutableListIfNecessary(List<List<String>> head) {
}

/**
* You can only choose one of the {@link #head(List)} and {@link #head(Class)}
* You can only choose one of the ({@link #head(List)} or {@link #head(Consumer)}) and {@link #head(Class)}
*
* @param clazz
* @return
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.fesod.sheet.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.apache.commons.lang3.Validate;

/**
* Standard implementation of {@code HeadBuilder}.
*/
class DefaultHeadBuilder implements HeadBuilder {

private final List<List<String>> columns;
private final List<String> prefixes;

DefaultHeadBuilder() {
this(new ArrayList<>(), new ArrayList<>());
}

DefaultHeadBuilder(List<List<String>> columns, List<String> prefixes) {
this.columns = columns;
this.prefixes = prefixes;
}

static List<List<String>> define(Consumer<HeadBuilder> headBuilderConsumer) {
Validate.notNull(headBuilderConsumer, "headBuilderConsumer must not be null");

DefaultHeadBuilder builder = new DefaultHeadBuilder();
headBuilderConsumer.accept(builder);
return builder.toHead();
}

/**
* Define a single column with a fixed head names (containing at least one column).
*
* @param headName the first header name (must not be {@code null})
* @param subHeadNames optional sublevel header names
* @return this for builder chains
*/
@Override
public HeadBuilder column(String headName, String... subHeadNames) {
Validate.notNull(headName, "header name must not be null");

int initialCapacity = prefixes.size() + ((subHeadNames == null) ? 0 : subHeadNames.length) + 1;
List<String> current = new ArrayList<>(initialCapacity);
current.addAll(prefixes);
current.add(headName);

if (subHeadNames != null) {
Validate.noNullElements(subHeadNames, "sub-header names must not contain null elements");
Collections.addAll(current, subHeadNames);
}
columns.add(current);
return this;
}

/**
* Define a single column with a repeating header name at multiple levels.
*
* @param headName the header name to repeat (must not be {@code null})
* @param repeat the number of times to repeat the name
* @return this for builder chains
*/
@Override
public HeadBuilder column(String headName, int repeat) {
Validate.notNull(headName, "header name must not be null");
Validate.isTrue(repeat > 0, "header repeat must be greater than 0");

int initialCapacity = prefixes.size() + repeat;
List<String> current = new ArrayList<>(initialCapacity);
current.addAll(prefixes);

for (int i = 0; i < repeat; i++) {
current.add(headName);
}

columns.add(current);
return this;
}

/**
* Declare multiple shared parent header names to group sub-headers.
*
* @param parentHeadNames the shared parent header names (must not be {@code null} or empty)
* @param subHeadBuilderConsumer the consumer to define sub-headers
* @return this for builder chains
*/
@Override
public HeadBuilder columns(List<String> parentHeadNames, Consumer<HeadBuilder> subHeadBuilderConsumer) {
Validate.notEmpty(parentHeadNames, "parent header names must not be null or empty");
Validate.noNullElements(parentHeadNames, "parent header names must not contain null elements");
Validate.notNull(subHeadBuilderConsumer, "subHeadBuilderConsumer must not be null");

int previousSize = this.prefixes.size();
this.prefixes.addAll(parentHeadNames);

subHeadBuilderConsumer.accept(this);

while (this.prefixes.size() > previousSize) {
this.prefixes.remove(this.prefixes.size() - 1);
}
return this;
}

/**
* Return the heads.
*
* @return the list of head
*/
List<List<String>> toHead() {
return columns;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.fesod.sheet.metadata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.apache.commons.lang3.Validate;

/**
* A builder for configuring sheet headers in No-Bean mode.
*
* <p>Example - complex headers:</p>
* <pre>
* {@code FesodSheet.write(pathname)
* .head(builder -> builder
* .column("ID", 2)
* .columns("User Info", sub -> sub.column("Name").column("Age"))
* .column("Others", "Remark")
* )
* // Equivalent to:
* List<List<String>> head = new ArrayList<>();
* head.add(new ArrayList<>(Arrays.asList("ID", "ID")));
* head.add(new ArrayList<>(Arrays.asList("User Info", "Name")));
* head.add(new ArrayList<>(Arrays.asList("User Info", "Age")));
* head.add(new ArrayList<>(Arrays.asList("Others", "Remark")));
*
* FesodSheet.write(pathname)
* .head(head)}
* </pre>
*
* <p>Example - single-level headers:</p>
* <pre>
* {@code FesodSheet.write(pathname)
* .head(HeadBuilder.forSimple("ID", "Name", "Age", "Remark"))
* // Equivalent to:
* List<List<String>> head = new ArrayList<>();
* head.add(new ArrayList<>(Arrays.asList("ID")));
* head.add(new ArrayList<>(Arrays.asList("Name")));
* head.add(new ArrayList<>(Arrays.asList("Age")));
* head.add(new ArrayList<>(Arrays.asList("Remark")));
*
* FesodSheet.write(pathname)
* .head(head)}
* </pre>
*
* @see AbstractParameterBuilder#head(Consumer)
*/
public interface HeadBuilder {

/**
* Define a single column with a fixed head names (containing at least one column).
*
* @param headName the first header name (must not be {@code null})
* @param subHeadNames optional sublevel header names
* @return this for builder chains
*/
HeadBuilder column(String headName, String... subHeadNames);

/**
* Define a single column with a repeating header name at multiple levels.
*
* @param headName the header name to repeat (must not be {@code null})
* @param repeat the number of times to repeat the name
* @return this for builder chains
*/
HeadBuilder column(String headName, int repeat);

/**
* Declare a shared parent header name to group sub-headers.
*
* @param parentHeadName the shared parent header name (must not be {@code null})
* @param subHeadBuilderConsumer the consumer to define sub-headers
* @return this for builder chains
*/
default HeadBuilder columns(String parentHeadName, Consumer<HeadBuilder> subHeadBuilderConsumer) {
return columns(Collections.singletonList(parentHeadName), subHeadBuilderConsumer);
}

/**
* Declare multiple shared parent header names to group sub-headers.
*
* @param parentHeadNames the shared parent header names (must not be {@code null} or empty)
* @param subHeadBuilderConsumer the consumer to define sub-headers
* @return this for builder chains
*/
HeadBuilder columns(List<String> parentHeadNames, Consumer<HeadBuilder> subHeadBuilderConsumer);

/**
* Build a simple single-level header list (containing at least one column).
*
* @param headName the first header name (must not be {@code null})
* @param otherHeadNames optional other header names
* @return a simple single-level header list
*/
static List<List<String>> forSimple(String headName, String... otherHeadNames) {
Validate.notNull(headName, "header name must not be null");

int initialCapacity = ((otherHeadNames == null) ? 0 : otherHeadNames.length) + 1;
List<List<String>> result = new ArrayList<>(initialCapacity);

List<String> firstHead = new ArrayList<>(1);
firstHead.add(headName);
result.add(firstHead);

if (otherHeadNames != null) {
Validate.noNullElements(otherHeadNames, "other header names must not contain null elements");
for (String otherHeadName : otherHeadNames) {
List<String> otherHead = new ArrayList<>(1);
otherHead.add(otherHeadName);
result.add(otherHead);
}
}
return result;
}
}
Loading
Loading