diff --git a/pom.xml b/pom.xml index f96cada..af99225 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,6 @@ spannm - 3.14.0 1.3.0 4.1.2 @@ -116,11 +115,6 @@ - - org.apache.commons - commons-lang3 - ${dep.commons-lang3.version} - commons-logging commons-logging diff --git a/src/main/java/io/github/spannm/jackcess/impl/ColumnImpl.java b/src/main/java/io/github/spannm/jackcess/impl/ColumnImpl.java index e946c4d..5eb4f6a 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/ColumnImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/ColumnImpl.java @@ -25,7 +25,7 @@ import io.github.spannm.jackcess.impl.expr.NumberFormatter; import io.github.spannm.jackcess.util.ColumnValidator; import io.github.spannm.jackcess.util.SimpleColumnValidator; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -1624,21 +1624,18 @@ private static byte getColumnBitFlags(ColumnBuilder col) { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.builder(this) - .append("name", "(" + _table.getName() + ") " + _name); - byte typeValue = getOriginalDataType(); - sb.append("type", "0x" + Integer.toHexString(typeValue) + " (" + _type + ")") - .append("number", _columnNumber) - .append("length", _columnLength) - .append("variableLength", _variableLength); + ToStringBuilder sb = ToStringBuilder.builder(this) + .append("name", "(" + _table.getName() + ") " + _name) + .append("type", "0x" + Integer.toHexString(getOriginalDataType()) + " (" + _type + ")") + .append("number", _columnNumber) + .append("length", _columnLength) + .append("variableLength", _variableLength); if (_calculated) { sb.append("calculated", _calculated) - .append("expression", - CustomToStringStyle.ignoreNull(getCalculationContext())); + .appendIgnoreNull("expression", getCalculationContext()); } if (_type.isTextual()) { - sb.append("compressedUnicode", isCompressedUnicode()) - .append("textSortOrder", getTextSortOrder()); + sb.append("compressedUnicode", isCompressedUnicode()).append("textSortOrder", getTextSortOrder()); if (getTextCodePage() > 0) { sb.append("textCodePage", getTextCodePage()); } @@ -1651,16 +1648,16 @@ public String toString() { } if (_type.getHasScalePrecision()) { sb.append("precision", getPrecision()) - .append("scale", getScale()); + .append("scale", getScale()); } if (_autoNumber) { sb.append("lastAutoNumber", _autoNumberGenerator.getLast()); } - sb.append("complexInfo", CustomToStringStyle.ignoreNull(getComplexInfo())) - .append("validator", CustomToStringStyle.ignoreNull( - _validator != SimpleColumnValidator.INSTANCE ? _validator : null)) - .append("defaultValue", CustomToStringStyle.ignoreNull(_defValue)); - return sb.toString(); + return sb + .appendIgnoreNull("complexInfo", getComplexInfo()) + .appendIgnoreNull("validator", _validator != SimpleColumnValidator.INSTANCE ? _validator : null) + .appendIgnoreNull("defaultValue", _defValue) + .toString(); } /** @@ -2217,7 +2214,7 @@ public byte[] getBytes() { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this) + return ToStringBuilder.valueBuilder(this) .append(null, getBytes()) .toString(); } @@ -2490,7 +2487,7 @@ public boolean equals(Object o) { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this) + return ToStringBuilder.valueBuilder(this) .append(null, _value + "(" + _version + ")") .toString(); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/CompoundOleUtil.java b/src/main/java/io/github/spannm/jackcess/impl/CompoundOleUtil.java index cdd4871..debebeb 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/CompoundOleUtil.java +++ b/src/main/java/io/github/spannm/jackcess/impl/CompoundOleUtil.java @@ -23,7 +23,7 @@ import io.github.spannm.jackcess.util.MemFileChannel; import io.github.spannm.jackcess.util.OleBlob.CompoundContent; import io.github.spannm.jackcess.util.OleBlob.ContentType; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentInputStream; @@ -185,7 +185,7 @@ private List getEntries(List entries, DirectoryEntry dir, // .. recurse into this directory getEntries(entries, (DirectoryEntry) entry, prefix + ENTRY_SEPARATOR); } else if (entry instanceof DocumentEntry) { - // grab the entry name/detils + // grab the entry name/details DocumentEntry de = (DocumentEntry) entry; String entryName = prefix + encodeEntryName(entry.getName()); entries.add(new EntryImpl(entryName, de)); @@ -203,13 +203,11 @@ public void close() { @Override public String toString() { - ToStringBuilder sb = toString(CustomToStringStyle.builder(this)); + ToStringBuilder sb = toString(ToStringBuilder.builder(this)); try { - sb.append("hasContentsEntry", hasContentsEntry()); - sb.append("entries", getEntries(new ArrayList<>(), - getFileSystem().getRoot(), - ENTRY_SEPARATOR)); + sb.append("hasContentsEntry", hasContentsEntry()) + .append("entries", getEntries(new ArrayList(), getFileSystem().getRoot(), ENTRY_SEPARATOR)); } catch (IOException e) { sb.append("entries", "<" + e + ">"); } @@ -265,7 +263,7 @@ public void writeTo(OutputStream out) throws IOException { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this) + return ToStringBuilder.valueBuilder(this) .append("name", _name) .append("length", length()) .toString(); diff --git a/src/main/java/io/github/spannm/jackcess/impl/CustomToStringStyle.java b/src/main/java/io/github/spannm/jackcess/impl/CustomToStringStyle.java deleted file mode 100644 index 20af8b4..0000000 --- a/src/main/java/io/github/spannm/jackcess/impl/CustomToStringStyle.java +++ /dev/null @@ -1,208 +0,0 @@ -/* -Copyright (c) 2013 James Ahlborn - -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 - - 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 io.github.spannm.jackcess.impl; - -import org.apache.commons.lang3.builder.StandardToStringStyle; -import org.apache.commons.lang3.builder.ToStringBuilder; - -import java.nio.ByteBuffer; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; - -/** - * Custom ToStringStyle for use with ToStringBuilder. - * - * @author James Ahlborn - */ -public class CustomToStringStyle extends StandardToStringStyle { - private static final long serialVersionUID = 0L; - - private static final String ML_FIELD_SEP = System.lineSeparator() + " "; - private static final String IMPL_SUFFIX = "Impl"; - private static final int MAX_BYTE_DETAIL_LEN = 20; - private static final Object IGNORE_ME = new Object(); - - public static final CustomToStringStyle INSTANCE = new CustomToStringStyle() { - private static final long serialVersionUID = 0L; - { - setContentStart("["); - setFieldSeparator(ML_FIELD_SEP); - setFieldSeparatorAtStart(true); - setFieldNameValueSeparator(": "); - setArraySeparator("," + ML_FIELD_SEP); - setContentEnd(System.lineSeparator() + "]"); - setUseShortClassName(true); - } - }; - - public static final CustomToStringStyle VALUE_INSTANCE = new CustomToStringStyle() { - private static final long serialVersionUID = 0L; - { - setUseShortClassName(true); - setUseIdentityHashCode(false); - } - }; - - private CustomToStringStyle() { - } - - public static ToStringBuilder builder(Object obj) { - return new ToStringBuilder(obj, INSTANCE); - } - - public static ToStringBuilder valueBuilder(Object obj) { - return new ToStringBuilder(obj, VALUE_INSTANCE); - } - - @Override - public void append(StringBuffer buffer, String fieldName, Object value, - Boolean fullDetail) { - if (value == IGNORE_ME) { - return; - } - super.append(buffer, fieldName, value, fullDetail); - } - - @Override - protected void appendClassName(StringBuffer buffer, Object obj) { - if (obj instanceof String) { - // the caller gave an "explicit" class name - buffer.append(obj); - } else { - super.appendClassName(buffer, obj); - } - } - - @Override - protected String getShortClassName(Class clss) { - String shortName = super.getShortClassName(clss); - if (shortName.endsWith(IMPL_SUFFIX)) { - shortName = shortName.substring(0, - shortName.length() - IMPL_SUFFIX.length()); - } - int idx = shortName.lastIndexOf('.'); - if (idx >= 0) { - shortName = shortName.substring(idx + 1); - } - return shortName; - } - - @Override - protected void appendDetail(StringBuffer buffer, String fieldName, - Object value) { - if (value instanceof ByteBuffer) { - appendDetail(buffer, (ByteBuffer) value); - } else { - buffer.append(indent(value)); - } - } - - @Override - protected void appendDetail(StringBuffer buffer, String fieldName, - Collection value) { - buffer.append("["); - - // gather contents of list in a new StringBuffer - StringBuffer sb = new StringBuffer(); - Iterator iter = value.iterator(); - if (iter.hasNext()) { - if (isFieldSeparatorAtStart()) { - appendFieldSeparator(sb); - } - appendValueDetail(sb, fieldName, iter.next()); - } - while (iter.hasNext()) { - sb.append(getArraySeparator()); - appendValueDetail(sb, fieldName, iter.next()); - } - - // indent entire list contents another level - buffer.append(indent(sb)); - - if (isFieldSeparatorAtStart()) { - appendFieldSeparator(buffer); - } - buffer.append("]"); - } - - @Override - protected void appendDetail(StringBuffer buffer, String fieldName, - Map value) { - buffer.append("{"); - - // gather contents of map in a new StringBuffer - StringBuffer sb = new StringBuffer(); - Iterator> iter = value.entrySet().iterator(); - if (iter.hasNext()) { - if (isFieldSeparatorAtStart()) { - appendFieldSeparator(sb); - } - Map.Entry e = iter.next(); - sb.append(e.getKey()).append("="); - appendValueDetail(sb, fieldName, e.getValue()); - } - while (iter.hasNext()) { - sb.append(getArraySeparator()); - Map.Entry e = iter.next(); - sb.append(e.getKey()).append("="); - appendValueDetail(sb, fieldName, e.getValue()); - } - - // indent entire map contents another level - buffer.append(indent(sb)); - - if (isFieldSeparatorAtStart()) { - appendFieldSeparator(buffer); - } - buffer.append("}"); - } - - @Override - protected void appendDetail(StringBuffer buffer, String fieldName, - byte[] array) { - appendDetail(buffer, PageChannel.wrap(array)); - } - - private void appendValueDetail(StringBuffer buffer, String fieldName, - Object value) { - if (value == null) { - appendNullText(buffer, fieldName); - } else { - appendInternal(buffer, fieldName, value, true); - } - } - - private static void appendDetail(StringBuffer buffer, ByteBuffer bb) { - int len = bb.remaining(); - buffer.append("(").append(len).append(") "); - buffer.append(ByteUtil.toHexString(bb, bb.position(), - Math.min(len, MAX_BYTE_DETAIL_LEN))); - if (len > MAX_BYTE_DETAIL_LEN) { - buffer.append(" ..."); - } - } - - private static String indent(Object obj) { - return obj != null ? obj.toString().replaceAll( - System.lineSeparator(), ML_FIELD_SEP) : null; - } - - public static Object ignoreNull(Object obj) { - return obj != null ? obj : IGNORE_ME; - } -} diff --git a/src/main/java/io/github/spannm/jackcess/impl/DatabaseImpl.java b/src/main/java/io/github/spannm/jackcess/impl/DatabaseImpl.java index c537c59..af17ec6 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/DatabaseImpl.java @@ -21,8 +21,6 @@ import io.github.spannm.jackcess.impl.query.QueryImpl; import io.github.spannm.jackcess.query.Query; import io.github.spannm.jackcess.util.*; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -953,7 +951,7 @@ public FileFormat getFileFormat() throws IOException { // need to check the "AccessVersion" property String accessVersion = (String) getDatabaseProperties().getValue(PropertyMap.ACCESS_VERSION_PROP); - if (isBlank(accessVersion)) { + if (StringUtil.isBlank(accessVersion)) { // no access version, fall back to "generic" accessVersion = null; } @@ -1856,7 +1854,7 @@ public static void validateIdentifierName(String name, int maxLength, String ide * Validates a name. */ private static void validateName(String name, int maxLength, String nameType) { - if (isBlank(name)) { + if (StringUtil.isBlank(name)) { throw new IllegalArgumentException(nameType + " must have non-blank name"); } if (name.length() > maxLength) { @@ -1864,24 +1862,9 @@ private static void validateName(String name, int maxLength, String nameType) { } } - /** - * Returns {@code true} if the given string is {@code null} or all blank space, {@code false} otherwise. - */ - public static boolean isBlank(String name) { - return StringUtils.isBlank(name); - } - - /** - * Returns the given string trimmed, or {@code null} if the string is {@code - * null} or empty. - */ - public static String trimToNull(String str) { - return StringUtils.trimToNull(str); - } - @Override public String toString() { - return ToStringBuilder.reflectionToString(this); + return StringUtil.reflectionToString(this); } /** @@ -2198,12 +2181,16 @@ public TableDefinition getTableDefinition(Database db) throws IOException { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.valueBuilder("TableMetaData").append("name", getName()); + ToStringBuilder sb = ToStringBuilder.valueBuilder("TableMetaData") + .append("name", getName()); if (isSystem()) { sb.append("isSystem", isSystem()); } if (isLinked()) { - sb.append("isLinked", isLinked()).append("linkedTableName", getLinkedTableName()).append("linkedDbName", getLinkedDbName()).append("connectionName", maskPassword(getConnectionName())); + sb.append("isLinked", isLinked()) + .append("linkedTableName", getLinkedTableName()) + .append("linkedDbName", getLinkedDbName()) + .append("connectionName", maskPassword(getConnectionName())); } return sb.toString(); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/IndexData.java b/src/main/java/io/github/spannm/jackcess/impl/IndexData.java index 5799f8c..1dfc145 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/IndexData.java +++ b/src/main/java/io/github/spannm/jackcess/impl/IndexData.java @@ -22,7 +22,7 @@ import io.github.spannm.jackcess.Index; import io.github.spannm.jackcess.IndexBuilder; import io.github.spannm.jackcess.impl.ByteUtil.ByteStream; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -66,14 +66,7 @@ public class IndexData { protected static final byte[] EMPTY_PREFIX = new byte[0]; - private static final byte[] ASC_EXT_DATE_TRAILER = { - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x02}; + private static final byte[] ASC_EXT_DATE_TRAILER = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}; private static final byte[] DESC_EXT_DATE_TRAILER = flipBytes(ByteUtil.copyOf(ASC_EXT_DATE_TRAILER, ASC_EXT_DATE_TRAILER.length)); static final short COLUMN_UNUSED = -1; @@ -83,9 +76,7 @@ public class IndexData { public static final byte UNIQUE_INDEX_FLAG = (byte) 0x01; public static final byte IGNORE_NULLS_INDEX_FLAG = (byte) 0x02; public static final byte REQUIRED_INDEX_FLAG = (byte) 0x08; - public static final byte UNKNOWN_INDEX_FLAG = (byte) 0x80; // always seems to be set - // on indexes in access - // 2000+ + public static final byte UNKNOWN_INDEX_FLAG = (byte) 0x80; // always seems to be set on indexes in access 2000+ private static final int MAGIC_INDEX_NUMBER = 1923; @@ -116,26 +107,26 @@ public enum EntryType { } public static final Comparator BYTE_CODE_COMPARATOR = (left, right) -> { - if (left == right) { - return 0; - } - if (left == null) { - return -1; - } - if (right == null) { - return 1; - } - - int len = Math.min(left.length, right.length); - int pos = 0; - while (pos < len && left[pos] == right[pos]) { - ++pos; - } - if (pos < len) { - return ByteUtil.asUnsignedByte(left[pos]) < ByteUtil.asUnsignedByte(right[pos]) ? -1 : 1; - } - return left.length < right.length ? -1 : left.length > right.length ? 1 : 0; - }; + if (left == right) { + return 0; + } + if (left == null) { + return -1; + } + if (right == null) { + return 1; + } + + int len = Math.min(left.length, right.length); + int pos = 0; + while (pos < len && left[pos] == right[pos]) { + ++pos; + } + if (pos < len) { + return ByteUtil.asUnsignedByte(left[pos]) < ByteUtil.asUnsignedByte(right[pos]) ? -1 : 1; + } + return left.length < right.length ? -1 : left.length > right.length ? 1 : 0; + }; /** name, generated on demand */ private String _name; @@ -960,8 +951,14 @@ public Object[] constructPartialIndexRow(Object filler, Map row) { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.builder(this).append("dataNumber", _number).append("pageNumber", _rootPageNumber).append("isBackingPrimaryKey", isBackingPrimaryKey()) - .append("isUnique", isUnique()).append("ignoreNulls", shouldIgnoreNulls()).append("isRequired", isRequired()).append("columns", _columns).append("initialized", _initialized); + ToStringBuilder sb = ToStringBuilder.builder(this) + .append("dataNumber", _number) + .append("pageNumber", _rootPageNumber) + .append("isBackingPrimaryKey", isBackingPrimaryKey()) + .append("isUnique", isUnique()) + .append("ignoreNulls", shouldIgnoreNulls()) + .append("isRequired", isRequired()) + .append("columns", _columns).append("initialized", _initialized); if (_initialized) { try { sb.append("entryCount", getEntryCount()); @@ -969,8 +966,8 @@ public String toString() { throw new UncheckedIOException(e); } } - sb.append("pageCache", _pageCache); - return sb.toString(); + return sb.append("pageCache", _pageCache) + .toString(); } /** @@ -1459,7 +1456,7 @@ protected final void writeValue(Object value, ByteStream bout) throws IOExceptio @Override public String toString() { - return CustomToStringStyle.builder(this).append("column", getColumn()).append("flags", getFlags() + " " + (isAscending() ? "(ASC)" : "(DSC)")).toString(); + return ToStringBuilder.builder(this).append("column", getColumn()).append("flags", getFlags() + " " + (isAscending() ? "(ASC)" : "(DSC)")).toString(); } } @@ -1880,7 +1877,7 @@ protected final ToStringBuilder entryBytesToStringBuilder(ToStringBuilder sb) { @Override public String toString() { - return entryBytesToStringBuilder(CustomToStringStyle.valueBuilder(this).append("rowId", _rowId)).toString(); + return entryBytesToStringBuilder(ToStringBuilder.valueBuilder(this).append("rowId", _rowId)).toString(); } @Override @@ -2009,7 +2006,7 @@ public int hashCode() { @Override public String toString() { - return entryBytesToStringBuilder(CustomToStringStyle.valueBuilder(this).append("rowId", getRowId()).append("subPage", _subPageNumber)).toString(); + return entryBytesToStringBuilder(ToStringBuilder.valueBuilder(this).append("rowId", getRowId()).append("subPage", _subPageNumber)).toString(); } } @@ -2213,7 +2210,10 @@ private void updateBounds() throws IOException { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this).append("curPosition", _curPos).append("prevPosition", _prevPos).toString(); + return ToStringBuilder.valueBuilder(this) + .append("curPosition", _curPos) + .append("prevPosition", _prevPos) + .toString(); } /** @@ -2361,7 +2361,12 @@ public boolean equals(Object o) { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this).append("page", _dataPage.getPageNumber()).append("idx", _idx).append("entry", _entry).append("between", _between).toString(); + return ToStringBuilder.valueBuilder(this) + .append("page", _dataPage.getPageNumber()) + .append("idx", _idx) + .append("entry", _entry) + .append("between", _between) + .toString(); } } @@ -2434,7 +2439,7 @@ public final String toString() { List entries = getEntries(); String objName = (isLeaf() ? "Leaf" : "Node") + "DataPage[" + getPageNumber() + "] " + getPrevPageNumber() + ", " + getNextPageNumber() + ", (" + getChildTailPageNumber() + ")"; - ToStringBuilder sb = CustomToStringStyle.valueBuilder(objName); + ToStringBuilder sb = ToStringBuilder.valueBuilder(objName); if (isLeaf() && !entries.isEmpty()) { sb.append("entryRange", "[" + entries.get(0) + ", " + entries.get(entries.size() - 1) + "]"); diff --git a/src/main/java/io/github/spannm/jackcess/impl/IndexImpl.java b/src/main/java/io/github/spannm/jackcess/impl/IndexImpl.java index 14dc7d9..b2c3f75 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/IndexImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/IndexImpl.java @@ -19,7 +19,7 @@ import io.github.spannm.jackcess.CursorBuilder; import io.github.spannm.jackcess.Index; import io.github.spannm.jackcess.IndexBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -341,7 +341,7 @@ public Object[] constructPartialIndexRow(Object filler, Map row) { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.builder(this) + ToStringBuilder sb = ToStringBuilder.builder(this) .append("name", "(" + getTable().getName() + ") " + _name) .append("number", _indexNumber) .append("isPrimaryKey", isPrimaryKey()) @@ -479,7 +479,7 @@ public boolean isCascadeNullOnDelete() { @Override public String toString() { - return CustomToStringStyle.builder(this) + return ToStringBuilder.builder(this) .append("otherIndexNumber", _otherIndexNumber) .append("otherTablePageNum", _otherTablePageNumber) .append("isPrimaryTable", isPrimaryTable()) diff --git a/src/main/java/io/github/spannm/jackcess/impl/IndexPageCache.java b/src/main/java/io/github/spannm/jackcess/impl/IndexPageCache.java index 713c0be..5943f4c 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/IndexPageCache.java +++ b/src/main/java/io/github/spannm/jackcess/impl/IndexPageCache.java @@ -20,7 +20,7 @@ import io.github.spannm.jackcess.impl.IndexData.DataPage; import io.github.spannm.jackcess.impl.IndexData.Entry; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.IOException; import java.lang.ref.Reference; @@ -907,13 +907,9 @@ private void purgeOldPages() { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.builder(this); - if (_rootPage == null) { - sb.append("pages", "(uninitialized)"); - } else { - sb.append("pages", collectPages(new ArrayList<>(), _rootPage)); - } - return sb.toString(); + return ToStringBuilder.builder(this) + .append("pages", _rootPage == null ? "(uninitialized)" : collectPages(new ArrayList<>(), _rootPage)) + .toString(); } private String withErrorContext(String msg) { @@ -1065,7 +1061,7 @@ public void updateEntryPrefix() { @Override public String toString() { - return CustomToStringStyle.builder("DPExtra").append(null, _entryView).toString(); + return ToStringBuilder.builder("DPExtra").append(null, _entryView).toString(); } } diff --git a/src/main/java/io/github/spannm/jackcess/impl/OleUtil.java b/src/main/java/io/github/spannm/jackcess/impl/OleUtil.java index a811487..0f673b1 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/OleUtil.java +++ b/src/main/java/io/github/spannm/jackcess/impl/OleUtil.java @@ -19,7 +19,7 @@ import io.github.spannm.jackcess.DataType; import io.github.spannm.jackcess.util.OleBlob; import io.github.spannm.jackcess.util.OleBlob.*; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.*; import java.nio.ByteBuffer; @@ -551,12 +551,12 @@ private static int fromJdbcOffset(long off) { @Override public String toString() { - ToStringBuilder sb = CustomToStringStyle.builder(this); + ToStringBuilder sb = ToStringBuilder.builder(this); if (_content != null) { sb.append("content", _content); } else { - sb.append("bytes", _bytes); - sb.append("content", "(uninitialized)"); + sb.append("bytes", _bytes) + .append("content", "(uninitialized)"); } return sb.toString(); } @@ -659,16 +659,14 @@ public String getTypeName() { @Override protected ToStringBuilder toString(ToStringBuilder sb) { sb.append("prettyName", _prettyName) - .append("className", _className) - .append("typeName", _typeName); + .append("className", _className) + .append("typeName", _typeName); super.toString(sb); return sb; } } - private static final class LinkContentImpl - extends EmbeddedPackageContentImpl - implements LinkContent { + private static final class LinkContentImpl extends EmbeddedPackageContentImpl implements LinkContent { private final String _fileName; private final String _linkPath; private final String _filePath; @@ -710,7 +708,7 @@ public InputStream getLinkStream() throws IOException { @Override public String toString() { - return toString(CustomToStringStyle.builder(this)) + return toString(ToStringBuilder.builder(this)) .append("fileName", _fileName) .append("linkPath", _linkPath) .append("filePath", _filePath) @@ -758,7 +756,7 @@ public String getLocalFilePath() { @Override public String toString() { - return toString(CustomToStringStyle.builder(this)) + return toString(ToStringBuilder.builder(this)) .append("fileName", _fileName) .append("filePath", _filePath) .append("localFilePath", _localFilePath) @@ -766,9 +764,7 @@ public String toString() { } } - private static final class OtherContentImpl - extends EmbeddedPackageContentImpl - implements OtherContent { + private static final class OtherContentImpl extends EmbeddedPackageContentImpl implements OtherContent { private OtherContentImpl( OleBlobImpl blob, String prettyName, String className, String typeName, int position, int length) { @@ -782,7 +778,7 @@ public ContentType getType() { @Override public String toString() { - return toString(CustomToStringStyle.builder(this)) + return toString(ToStringBuilder.builder(this)) .toString(); } } @@ -799,7 +795,7 @@ public ContentType getType() { @Override public String toString() { - return toString(CustomToStringStyle.builder(this)) + return toString(ToStringBuilder.builder(this)) .append("content", _blob._bytes) .toString(); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/PropertyMaps.java b/src/main/java/io/github/spannm/jackcess/impl/PropertyMaps.java index 981c61b..73c151d 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/PropertyMaps.java +++ b/src/main/java/io/github/spannm/jackcess/impl/PropertyMaps.java @@ -18,6 +18,8 @@ import io.github.spannm.jackcess.DataType; import io.github.spannm.jackcess.PropertyMap; +import io.github.spannm.jackcess.util.StringUtil; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.IOException; import java.nio.ByteBuffer; @@ -111,14 +113,13 @@ public void save() throws IOException { @Override public String toString() { - return CustomToStringStyle.builder(this) + return ToStringBuilder.builder(this) .append(null, _maps.values()) .toString(); } - public static String getTrimmedStringProperty( - PropertyMap props, String propName) { - return DatabaseImpl.trimToNull((String) props.getValue(propName)); + public static String getTrimmedStringProperty(PropertyMap props, String propName) { + return StringUtil.trimToNull((String) props.getValue(propName)); } /** @@ -174,8 +175,7 @@ public PropertyMaps read(byte[] propBytes, int objectId, short type = bb.getShort(); int endPos = bb.position() + len - 6; - ByteBuffer bbBlock = PageChannel.narrowBuffer(bb, bb.position(), - endPos); + ByteBuffer bbBlock = PageChannel.narrowBuffer(bb, bb.position(), endPos); if (type == PROPERTY_NAME_LIST) { propNames = readPropertyNames(bbBlock); @@ -192,8 +192,7 @@ public PropertyMaps read(byte[] propBytes, int objectId, /** * @return a byte[] encoded from the given PropertyMaps instance */ - public byte[] write(PropertyMaps maps) - throws IOException { + public byte[] write(PropertyMaps maps) throws IOException { if (maps == null) { return null; } @@ -233,8 +232,7 @@ public byte[] write(PropertyMaps maps) public void save(PropertyMaps maps) throws IOException { RowIdImpl rowId = maps._rowId; if (rowId == null) { - throw new IllegalStateException( - "PropertyMaps cannot be saved without a row id"); + throw new IllegalStateException("PropertyMaps cannot be saved without a row id"); } byte[] mapsBytes = write(maps); diff --git a/src/main/java/io/github/spannm/jackcess/impl/RelationshipCreator.java b/src/main/java/io/github/spannm/jackcess/impl/RelationshipCreator.java index 5c9de15..d748256 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/RelationshipCreator.java +++ b/src/main/java/io/github/spannm/jackcess/impl/RelationshipCreator.java @@ -17,6 +17,7 @@ package io.github.spannm.jackcess.impl; import io.github.spannm.jackcess.*; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.IOException; import java.util.*; @@ -319,7 +320,7 @@ private static String getTableErrorContext( colNames = getColumnNames(cols); } - return CustomToStringStyle.valueBuilder(tableName) + return ToStringBuilder.valueBuilder(tableName) .append(null, colNames) .toString(); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/RelationshipImpl.java b/src/main/java/io/github/spannm/jackcess/impl/RelationshipImpl.java index af74613..4937b01 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/RelationshipImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/RelationshipImpl.java @@ -19,6 +19,7 @@ import io.github.spannm.jackcess.Column; import io.github.spannm.jackcess.Relationship; import io.github.spannm.jackcess.Table; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.util.ArrayList; import java.util.Collections; @@ -163,7 +164,7 @@ private boolean hasFlag(int flagMask) { @Override public String toString() { - return CustomToStringStyle.builder(this) + return ToStringBuilder.builder(this) .append("name", _name) .append("fromTable", _fromTable.getName()) .append("fromColumns", _fromColumns) diff --git a/src/main/java/io/github/spannm/jackcess/impl/RowIdImpl.java b/src/main/java/io/github/spannm/jackcess/impl/RowIdImpl.java index e0509f5..07b3a42 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/RowIdImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/RowIdImpl.java @@ -17,7 +17,6 @@ package io.github.spannm.jackcess.impl; import io.github.spannm.jackcess.RowId; -import org.apache.commons.lang3.builder.CompareToBuilder; import java.io.Serializable; @@ -104,11 +103,14 @@ public int compareTo(RowId other) { } public int compareTo(RowIdImpl other) { - return new CompareToBuilder() - .append(getType(), other.getType()) - .append(getPageNumber(), other.getPageNumber()) - .append(getRowNumber(), other.getRowNumber()) - .toComparison(); + int compare = getType().compareTo(other.getType()); + if (compare == 0) { + compare = Integer.compare(getPageNumber(), other.getPageNumber()); + } + if (compare == 0) { + compare = Integer.compare(getRowNumber(), other.getRowNumber()); + } + return compare; } @Override diff --git a/src/main/java/io/github/spannm/jackcess/impl/RowImpl.java b/src/main/java/io/github/spannm/jackcess/impl/RowImpl.java index af7cd93..f380eb3 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/RowImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/RowImpl.java @@ -19,6 +19,7 @@ import io.github.spannm.jackcess.Row; import io.github.spannm.jackcess.complex.ComplexValueForeignKey; import io.github.spannm.jackcess.util.OleBlob; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.IOException; import java.math.BigDecimal; @@ -127,7 +128,7 @@ public OleBlob getBlob(String name) throws IOException { @Override public String toString() { - return CustomToStringStyle.valueBuilder("Row[" + _id + "]") + return ToStringBuilder.valueBuilder("Row[" + _id + "]") .append(null, this) .toString(); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/TableImpl.java b/src/main/java/io/github/spannm/jackcess/impl/TableImpl.java index a8725c6..b1362cb 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/TableImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/TableImpl.java @@ -20,6 +20,7 @@ import io.github.spannm.jackcess.expr.Identifier; import io.github.spannm.jackcess.util.ErrorHandler; import io.github.spannm.jackcess.util.ExportUtil; +import io.github.spannm.jackcess.util.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -2918,14 +2919,14 @@ void restoreLastComplexTypeAutoNumber(int lastComplexTypeAutoNumber) { @Override public String toString() { - return CustomToStringStyle.builder(this) + return ToStringBuilder.builder(this) .append("type", _tableType + (!isSystem() ? " (USER)" : " (SYSTEM)")) .append("name", _name) .append("rowCount", _rowCount) .append("columnCount", _columns.size()) .append("indexCount(data)", _indexCount) .append("logicalIndexCount", _logicalIndexCount) - .append("validator", CustomToStringStyle.ignoreNull(_rowValidator)) + .appendIgnoreNull("validator", _rowValidator) .append("columns", _columns) .append("indexes", _indexes) .append("ownedPages", _ownedPages) @@ -3401,7 +3402,7 @@ private Object handleRowError(ColumnImpl column, byte[] columnData, @Override public String toString() { - return CustomToStringStyle.valueBuilder(this) + return ToStringBuilder.valueBuilder(this) .append("headerRowId", _headerRowId) .append("finalRowId", _finalRowId) .toString(); diff --git a/src/main/java/io/github/spannm/jackcess/impl/UsageMap.java b/src/main/java/io/github/spannm/jackcess/impl/UsageMap.java index 96f4394..b1ba73d 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/UsageMap.java +++ b/src/main/java/io/github/spannm/jackcess/impl/UsageMap.java @@ -16,6 +16,8 @@ package io.github.spannm.jackcess.impl; +import io.github.spannm.jackcess.util.ToStringBuilder; + import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -406,8 +408,7 @@ public String toString() { rangeToString(ranges, curRangeStart, prevPage); } - return CustomToStringStyle.valueBuilder( - _handler.getClass().getSimpleName()) + return ToStringBuilder.valueBuilder(_handler.getClass().getSimpleName()) .append("range", "(" + _startPage + "-" + _endPage + ")") .append("pageNumbers", ranges) .toString(); diff --git a/src/main/java/io/github/spannm/jackcess/impl/complex/ComplexColumnInfoImpl.java b/src/main/java/io/github/spannm/jackcess/impl/complex/ComplexColumnInfoImpl.java index e07445e..bf9b6c3 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/complex/ComplexColumnInfoImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/complex/ComplexColumnInfoImpl.java @@ -22,8 +22,8 @@ import io.github.spannm.jackcess.complex.ComplexValue; import io.github.spannm.jackcess.complex.ComplexValueForeignKey; import io.github.spannm.jackcess.impl.ColumnImpl; -import io.github.spannm.jackcess.impl.CustomToStringStyle; import io.github.spannm.jackcess.impl.TableImpl; +import io.github.spannm.jackcess.util.ToStringBuilder; import java.io.IOException; import java.util.*; @@ -287,7 +287,7 @@ private Object[] newRowArray() { @Override public String toString() { - return CustomToStringStyle.valueBuilder(this) + return ToStringBuilder.valueBuilder(this) .append("complexType", getType()) .append("complexTypeId", _complexTypeId) .toString(); diff --git a/src/main/java/io/github/spannm/jackcess/impl/expr/DefaultTextFunctions.java b/src/main/java/io/github/spannm/jackcess/impl/expr/DefaultTextFunctions.java index 16de089..4ccb1f4 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/expr/DefaultTextFunctions.java +++ b/src/main/java/io/github/spannm/jackcess/impl/expr/DefaultTextFunctions.java @@ -24,8 +24,11 @@ import io.github.spannm.jackcess.impl.expr.FunctionSupport.Func1NullIsNull; import io.github.spannm.jackcess.impl.expr.FunctionSupport.Func2; import io.github.spannm.jackcess.impl.expr.FunctionSupport.FuncVar; +import io.github.spannm.jackcess.util.StringUtil; import java.math.BigDecimal; +import java.util.Arrays; +import java.util.stream.Collectors; /** * @@ -383,16 +386,14 @@ protected Value evalVar(EvalContext ctx, Value[] params) { break; case 3: // vbProperCase - str = org.apache.commons.lang3.text.WordUtils.capitalize( - str.toLowerCase()); + str = Arrays.stream(str.toLowerCase().split(" ")).map(StringUtil::capitalize).collect(Collectors.joining(" ")); break; default: // do nothing } if (charConv != 0) { - // 64 = vbUnicode, all java strings are already unicode,so - // nothing to do + // 64 = vbUnicode, all java strings are already unicode, so nothing to do if (charConv != 64) { throw new EvalException("Unsupported character conversion " + charConv); } diff --git a/src/main/java/io/github/spannm/jackcess/impl/expr/ExpressionTokenizer.java b/src/main/java/io/github/spannm/jackcess/impl/expr/ExpressionTokenizer.java index 68b8dba..64a9b6f 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/expr/ExpressionTokenizer.java +++ b/src/main/java/io/github/spannm/jackcess/impl/expr/ExpressionTokenizer.java @@ -23,7 +23,7 @@ import io.github.spannm.jackcess.impl.ColumnImpl; import io.github.spannm.jackcess.impl.expr.Expressionator.ParseContext; import io.github.spannm.jackcess.impl.expr.Expressionator.Type; -import org.apache.commons.lang3.StringUtils; +import io.github.spannm.jackcess.util.StringUtil; import java.math.BigDecimal; import java.time.DateTimeException; @@ -79,14 +79,13 @@ private ExpressionTokenizer() { /** * Tokenizes an expression string of the given type and (optionally) in the context of the relevant database. */ - static List tokenize(Type exprType, String exprStr, - ParseContext context) { + static List tokenize(Type exprType, String exprStr, ParseContext context) { if (exprStr != null) { exprStr = exprStr.trim(); } - if (StringUtils.isEmpty(exprStr)) { + if (StringUtil.isEmpty(exprStr)) { return null; } @@ -139,8 +138,7 @@ static List tokenize(Type exprType, String exprStr, switch (c) { case QUOTED_STR_CHAR: case SINGLE_QUOTED_STR_CHAR: - tokens.add(new Token(TokenType.LITERAL, null, - parseQuotedString(buf, c), Value.Type.STRING)); + tokens.add(new Token(TokenType.LITERAL, null, parseQuotedString(buf, c), Value.Type.STRING)); break; case DATE_LIT_QUOTE_CHAR: tokens.add(parseDateLiteral(buf)); @@ -149,8 +147,7 @@ static List tokenize(Type exprType, String exprStr, tokens.add(new Token(TokenType.OBJ_NAME, parseObjNameString(buf))); break; default: - throw new ParseException( - "Invalid leading quote character " + c + " " + buf); + throw new ParseException("Invalid leading quote character " + c + " " + buf); } break; @@ -211,8 +208,7 @@ private static void consumeWhitespace(ExprBuf buf) { } } - private static String parseBareString(char firstChar, ExprBuf buf, - Type exprType) { + private static String parseBareString(char firstChar, ExprBuf buf, Type exprType) { StringBuilder sb = buf.getScratchBuffer().append(firstChar); byte stopFlags = IS_OP_FLAG | IS_DELIM_FLAG | IS_SPACE_FLAG; @@ -248,8 +244,7 @@ private static String parseDateLiteralString(ExprBuf buf) { static String parseStringUntil(ExprBuf buf, Character startChar, char endChar, boolean allowDoubledEscape) { return parseStringUntil(buf, startChar, endChar, allowDoubledEscape, - buf.getScratchBuffer()) - .toString(); + buf.getScratchBuffer()).toString(); } static StringBuilder parseStringUntil( @@ -449,8 +444,7 @@ static final class ExprBuf { private final ParseContext _ctx; private int _pos; private final Map _dateTimeFmts = - new EnumMap<>( - TemporalConfig.Type.class); + new EnumMap<>(TemporalConfig.Type.class); private final StringBuilder _scratch = new StringBuilder(); ExprBuf(String str, ParseContext ctx) { diff --git a/src/main/java/io/github/spannm/jackcess/impl/expr/Expressionator.java b/src/main/java/io/github/spannm/jackcess/impl/expr/Expressionator.java index c05a5f2..e1717bc 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/expr/Expressionator.java +++ b/src/main/java/io/github/spannm/jackcess/impl/expr/Expressionator.java @@ -19,7 +19,7 @@ import io.github.spannm.jackcess.expr.*; import io.github.spannm.jackcess.impl.expr.ExpressionTokenizer.Token; import io.github.spannm.jackcess.impl.expr.ExpressionTokenizer.TokenType; -import org.apache.commons.lang3.StringUtils; +import io.github.spannm.jackcess.util.StringUtil; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -1253,8 +1253,8 @@ private static boolean areConstant(Expr... exprs) { private static void literalStrToString(String str, StringBuilder sb) { sb.append("\"") - .append(StringUtils.replace(str, "\"", "\"\"")) - .append("\""); + .append(StringUtil.replace(str, "\"", "\"\"")) + .append("\""); } /** diff --git a/src/main/java/io/github/spannm/jackcess/impl/expr/FormatUtil.java b/src/main/java/io/github/spannm/jackcess/impl/expr/FormatUtil.java index 9723428..2b94a51 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/expr/FormatUtil.java +++ b/src/main/java/io/github/spannm/jackcess/impl/expr/FormatUtil.java @@ -18,7 +18,7 @@ import io.github.spannm.jackcess.expr.*; import io.github.spannm.jackcess.impl.expr.ExpressionTokenizer.ExprBuf; -import org.apache.commons.lang3.StringUtils; +import io.github.spannm.jackcess.util.StringUtil; import java.math.BigDecimal; import java.text.DecimalFormat; @@ -431,7 +431,7 @@ private static Fmt createFormat(Args args, String fmtStr) { return predefFmt; } - if (StringUtils.isEmpty(fmtStr)) { + if (StringUtil.isEmpty(fmtStr)) { return DUMMY_FMT; } diff --git a/src/main/java/io/github/spannm/jackcess/impl/expr/StringValue.java b/src/main/java/io/github/spannm/jackcess/impl/expr/StringValue.java index db37f04..6ecbd3d 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/expr/StringValue.java +++ b/src/main/java/io/github/spannm/jackcess/impl/expr/StringValue.java @@ -19,7 +19,7 @@ import io.github.spannm.jackcess.expr.EvalException; import io.github.spannm.jackcess.expr.LocaleContext; import io.github.spannm.jackcess.expr.Value; -import org.apache.commons.lang3.StringUtils; +import io.github.spannm.jackcess.util.StringUtil; import java.math.BigDecimal; import java.text.DecimalFormatSymbols; @@ -145,7 +145,7 @@ private static String toCanonicalNumberFormat(LocaleContext ctx, String tmpVal) // - convert decimal separator to '.' DecimalFormatSymbols syms = ctx.getNumericConfig().getDecimalFormatSymbols(); char groupSepChar = syms.getGroupingSeparator(); - tmpVal = StringUtils.remove(tmpVal, groupSepChar); + tmpVal = StringUtil.remove(tmpVal, String.valueOf(groupSepChar)); char decSepChar = syms.getDecimalSeparator(); if (decSepChar != ValueSupport.CANON_DEC_SEP && tmpVal.indexOf(decSepChar) >= 0) { diff --git a/src/main/java/io/github/spannm/jackcess/impl/query/QueryImpl.java b/src/main/java/io/github/spannm/jackcess/impl/query/QueryImpl.java index 36799b2..166cf48 100644 --- a/src/main/java/io/github/spannm/jackcess/impl/query/QueryImpl.java +++ b/src/main/java/io/github/spannm/jackcess/impl/query/QueryImpl.java @@ -23,7 +23,7 @@ import io.github.spannm.jackcess.impl.RowIdImpl; import io.github.spannm.jackcess.impl.RowImpl; import io.github.spannm.jackcess.query.Query; -import org.apache.commons.lang3.builder.ToStringBuilder; +import io.github.spannm.jackcess.util.StringUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -337,7 +337,7 @@ public String toSQLString() { @Override public String toString() { - return ToStringBuilder.reflectionToString(this); + return StringUtil.reflectionToString(this); } /** @@ -350,8 +350,7 @@ public String toString() { * * @return a Query instance for the given query data */ - public static QueryImpl create(int objectFlag, String name, List rows, - int objectId) { + public static QueryImpl create(int objectFlag, String name, List rows, int objectId) { // remove other object flags before testing for query type int objTypeFlag = objectFlag & OBJECT_FLAG_MASK; @@ -387,8 +386,7 @@ public static QueryImpl create(int objectFlag, String name, List rows, return new UnionQueryImpl(name, rows, objectId, objectFlag); default: // unknown querytype - throw new IllegalStateException(withErrorContext( - "unknown query object flag " + objTypeFlag, name)); + throw new IllegalStateException(withErrorContext("unknown query object flag " + objTypeFlag, name)); } } catch (IllegalStateException e) { LOG.warn(withErrorContext("Failed parsing query", name), e); @@ -605,7 +603,7 @@ public io.github.spannm.jackcess.Row toTableRow() { @Override public String toString() { - return ToStringBuilder.reflectionToString(this); + return StringUtil.reflectionToString(this); } } diff --git a/src/main/java/io/github/spannm/jackcess/util/ColumnFormatter.java b/src/main/java/io/github/spannm/jackcess/util/ColumnFormatter.java index c8935e9..17cfd77 100644 --- a/src/main/java/io/github/spannm/jackcess/util/ColumnFormatter.java +++ b/src/main/java/io/github/spannm/jackcess/util/ColumnFormatter.java @@ -23,7 +23,6 @@ import io.github.spannm.jackcess.impl.ColEvalContext; import io.github.spannm.jackcess.impl.ColumnImpl; import io.github.spannm.jackcess.impl.expr.FormatUtil; -import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.util.Map; @@ -65,7 +64,7 @@ public String getFormatString() { */ public void setFormatString(String fmtStr) throws IOException { PropertyMap props = _col.getProperties(); - if (!StringUtils.isEmpty(fmtStr)) { + if (!StringUtil.isEmpty(fmtStr)) { props.put(PropertyMap.FORMAT_PROP, fmtStr); } else { props.remove(PropertyMap.FORMAT_PROP); diff --git a/src/main/java/io/github/spannm/jackcess/util/ImportUtil.java b/src/main/java/io/github/spannm/jackcess/util/ImportUtil.java index 600e314..0f554a6 100644 --- a/src/main/java/io/github/spannm/jackcess/util/ImportUtil.java +++ b/src/main/java/io/github/spannm/jackcess/util/ImportUtil.java @@ -17,7 +17,6 @@ package io.github.spannm.jackcess.util; import io.github.spannm.jackcess.*; -import io.github.spannm.jackcess.impl.DatabaseImpl; import java.io.*; import java.sql.ResultSet; @@ -383,7 +382,7 @@ public static String importReader(BufferedReader in, Database db, boolean useExistingTable, boolean header) throws IOException { String line = in.readLine(); - if (DatabaseImpl.isBlank(line)) { + if (StringUtil.isBlank(line)) { return null; } diff --git a/src/main/java/io/github/spannm/jackcess/util/SimpleImportFilter.java b/src/main/java/io/github/spannm/jackcess/util/SimpleImportFilter.java index 016e310..c72e607 100644 --- a/src/main/java/io/github/spannm/jackcess/util/SimpleImportFilter.java +++ b/src/main/java/io/github/spannm/jackcess/util/SimpleImportFilter.java @@ -36,9 +36,7 @@ public SimpleImportFilter() { } @Override - public List filterColumns(List destColumns, - ResultSetMetaData srcColumns) - throws SQLException, IOException { + public List filterColumns(List destColumns, ResultSetMetaData srcColumns) throws SQLException, IOException { return destColumns; } diff --git a/src/main/java/io/github/spannm/jackcess/util/StringUtil.java b/src/main/java/io/github/spannm/jackcess/util/StringUtil.java new file mode 100644 index 0000000..14f8e34 --- /dev/null +++ b/src/main/java/io/github/spannm/jackcess/util/StringUtil.java @@ -0,0 +1,141 @@ +package io.github.spannm.jackcess.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Comparator; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; + +/** + *

Static utility methods for null-safe {@link String} operations.

+ * + * The class prefers interface {@link CharSequence} for inputs over {@code String} whenever possible, so that all implementations (e.g. {@link StringBuffer}, {@link StringBuilder}, {@link CharBuffer}) + * can benefit. + * + * @author Markus Spann + */ +public final class StringUtil { + + private StringUtil() { + } + + /** + * Gets the given char sequence's length or {@code 0} if it is {@code null}. + * + * @param cs string + * @return length of string + */ + public static int length(CharSequence cs) { + return cs == null ? 0 : cs.length(); + } + + /** + * Checks if the given char sequence is either null or empty. + * + * @param cs char sequence to test + * @return true if char sequence is empty or null, false otherwise + */ + public static boolean isEmpty(CharSequence cs) { + return length(cs) == 0; + } + + /** + * Returns {@code true} if the given char sequence is {@code null} or all blank space, {@code false} otherwise. + */ + public static boolean isBlank(CharSequence cs) { + int len = length(cs); + return len == 0 || IntStream.range(0, len).allMatch(i -> Character.isWhitespace(cs.charAt(i))); + } + + /** + * Returns the given char sequence trimmed or {@code null} if the string is {@code null} or empty. + */ + public static String trimToNull(CharSequence cs) { + String str = cs == null ? null : cs.toString().trim(); + return isEmpty(str) ? null : str; + } + + /** + * Capitalizes a string changing its first character to title case as per {@link Character#toTitleCase(int)}. + */ + public static String capitalize(String str) { + if (isEmpty(str)) { + return str; + } + + int cp = str.codePointAt(0); + int newCp = Character.toTitleCase(cp); + return cp == newCp ? str : new String(Character.toString((char) newCp)) + str.substring(1); + } + + public static String replace(String text, CharSequence searchString, CharSequence replacement) { + return isEmpty(text) || isEmpty(searchString) ? text : text.replace(searchString, replacement); + } + + /** + * Removes all occurrences of character sequence {@code remove} from string {@code cs}. + * + * @param cs the character sequence to remove from + * @param remove the character sequence to remove + * @return modified input + */ + public static String remove(CharSequence cs, CharSequence remove) { + if (cs == null) { + return null; + } + int len = cs.length(); + if (len == 0) { + return ""; + } else if (isEmpty(remove) || remove.length() > len) { + return cs.toString(); + } + return cs.toString().replace(remove, ""); + } + + /** + * Generates a string representation of {@code obj} using reflection on its non-static declared fields. + * + * @param obj object to generate string from + * @param longClassName use full class name if {@code true} or simple name if {@code false} + * @param hashCode include the object's hash code if {@code true} + * @return string representation + */ + public static String reflectionToString(Object obj, boolean longClassName, boolean hashCode) { + if (obj == null) { + return "null"; + } + StringBuilder sb = new StringBuilder(longClassName ? obj.getClass().getName() : obj.getClass().getSimpleName()); + if (hashCode) { + sb.append('@').append(Integer.toHexString(System.identityHashCode(obj))); + } + sb.append('['); + AtomicBoolean firstField = new AtomicBoolean(true); + Arrays.stream(obj.getClass().getDeclaredFields()).filter(f -> !Modifier.isStatic(f.getModifiers())).sorted(Comparator.comparing(Field::getName)).forEach(f -> { + if (!firstField.compareAndSet(true, false)) { + sb.append(','); + } + sb.append(f.getName()).append('='); + try { + f.setAccessible(true); + Object val = f.get(obj); + sb.append(val == null ? "" : val); + } catch (Exception _ex) { + sb.append('<').append(_ex).append('>'); + } + }); + return sb.append(']').toString(); + } + + /** + * Generates a string representation of {@code obj} using reflection on its non-static declared fields using the object's full class name and including the object's hash code.
+ * + * @param obj object to generate string from + * @return string representation + */ + public static String reflectionToString(Object obj) { + return reflectionToString(obj, true, true); + } + +} diff --git a/src/main/java/io/github/spannm/jackcess/util/ToStringBuilder.java b/src/main/java/io/github/spannm/jackcess/util/ToStringBuilder.java new file mode 100644 index 0000000..36ca148 --- /dev/null +++ b/src/main/java/io/github/spannm/jackcess/util/ToStringBuilder.java @@ -0,0 +1,170 @@ +package io.github.spannm.jackcess.util; + +import io.github.spannm.jackcess.impl.ByteUtil; +import io.github.spannm.jackcess.impl.PageChannel; + +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.WeakHashMap; +import java.util.stream.Collectors; + +/** + *

Builder for {@link Object#toString()} methods.

+ * + * @author Markus Spann + */ +public class ToStringBuilder { + /** Object registry for avoidance of cycles. */ + private static final Map OBJ_REGISTRY = new WeakHashMap<>(); + + private final StringBuilder buffer; + private final Object object; + + private final String fieldSeparator; + private final boolean fieldSeparatorAtStart; + private final String fieldNameValueSeparator; + private final String contentStart; + private final String contentEnd; + private final String nullText; + private final String implSuffix; + private boolean useIdentityHashCode = true; + private final int maxByteDetailLen = 20; + + ToStringBuilder(Object _object, String _fieldSeparator, boolean _fieldSeparatorAtStart, String _fieldNameValueSeparator, String _contentEnd, boolean _useIdentityHashCode) { + buffer = new StringBuilder(512); + object = _object; + fieldSeparator = Optional.ofNullable(_fieldSeparator).orElse(","); + fieldSeparatorAtStart = _fieldSeparatorAtStart; + fieldNameValueSeparator = Optional.ofNullable(_fieldNameValueSeparator).orElse("="); + contentStart = "["; + contentEnd = Optional.ofNullable(_contentEnd).orElse("]"); + nullText = ""; + implSuffix = "Impl"; + useIdentityHashCode = _useIdentityHashCode; + + if (object != null) { + buffer.append(_object instanceof String ? _object : getShortClassName(_object.getClass(), implSuffix)); + if (useIdentityHashCode) { + buffer.append('@').append(Integer.toHexString(System.identityHashCode(object))); + } + + buffer.append(contentStart); + if (fieldSeparatorAtStart) { + buffer.append(fieldSeparator); + } + } + } + + public static ToStringBuilder valueBuilder(Object obj) { + return new ToStringBuilder(obj, null, false, null, null, false); + } + + public static ToStringBuilder builder(Object obj) { + return new ToStringBuilder(obj, System.lineSeparator() + " ", true, ": ", System.lineSeparator() + "]", true); + } + + public ToStringBuilder append(String fieldName, Object value) { + if (fieldName != null) { + buffer.append(fieldName).append(fieldNameValueSeparator); + } + + if (value == null) { + buffer.append(nullText); + } else { + appendInternal(buffer, fieldName, value); + } + + buffer.append(fieldSeparator); + return this; + } + + public ToStringBuilder appendIgnoreNull(String fieldName, Object value) { + return append(fieldName, value == null ? "" : value); + } + + @Override + public String toString() { + if (object == null) { + buffer.append(nullText); + } else { + removeLastFieldSeparator(buffer, fieldSeparator); + buffer.append(contentEnd); + } + return buffer.toString(); + } + + void appendInternal(StringBuilder _buffer, String _fieldName, Object _value) { + boolean primitiveWrapper = _value instanceof Number || _value instanceof Boolean || _value instanceof Character; + if (OBJ_REGISTRY.containsKey(_value) && !primitiveWrapper) { + _buffer.append(_value.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(_value))); + return; + } + + OBJ_REGISTRY.put(_value, null); // register object + + try { + if (_value instanceof byte[]) { + ByteBuffer bb = PageChannel.wrap((byte[]) _value); + int len = bb.remaining(); + _buffer.append("(").append(len).append(") ").append(ByteUtil.toHexString(bb, bb.position(), Math.min(len, maxByteDetailLen))); + if (len > maxByteDetailLen) { + _buffer.append("..."); + } + } else if (_value.getClass().isArray()) { + Object arr = _value; + _buffer.append('{'); + for (int i = 0; i < Array.getLength(arr); i++) { + Object item = Array.get(arr, i); + if (i > 0) { + _buffer.append(fieldSeparator); + } + if (item == null) { + _buffer.append(nullText); + } else { + appendInternal(_buffer, _fieldName, item); // recursive call + } + } + _buffer.append('}'); + } else if (_value instanceof Collection) { + String str = ((Collection) _value).stream().map(v -> v == null ? nullText : v.toString()).collect(Collectors.joining(",")); + _buffer.append('[').append(str).append(']'); + } else if (_value instanceof Map) { + String str = ((Map) _value).entrySet().stream().map(e -> e.getKey() + "=" + (e.getValue() == null ? nullText : e.getValue())).collect(Collectors.joining(",")); + _buffer.append('{').append(str).append('}'); + } else { + _buffer.append(_value); + } + } finally { + OBJ_REGISTRY.remove(_value); // unregister object + } + } + + static String getShortClassName(Class clazz, String _implSuffix) { + String nm = clazz.getSimpleName(); + if (nm.endsWith(_implSuffix)) { + nm = nm.substring(0, nm.length() - _implSuffix.length()); + } + int idx = nm.lastIndexOf('.'); + return idx >= 0 ? nm.substring(idx + 1) : nm; + } + + static void removeLastFieldSeparator(StringBuilder _buffer, String _fieldSeparator) { + int len = _buffer.length(); + int sepLen = _fieldSeparator.length(); + if (len > 0 && sepLen > 0 && len >= sepLen) { + boolean match = true; + for (int i = 0; i < sepLen; i++) { + if (_buffer.charAt(len - 1 - i) != _fieldSeparator.charAt(sepLen - 1 - i)) { + return; + } + } + if (match) { + _buffer.setLength(len - sepLen); + } + } + } + +} diff --git a/src/test/java/io/github/spannm/jackcess/DatabaseTest.java b/src/test/java/io/github/spannm/jackcess/DatabaseTest.java index 1559bea..397cf87 100644 --- a/src/test/java/io/github/spannm/jackcess/DatabaseTest.java +++ b/src/test/java/io/github/spannm/jackcess/DatabaseTest.java @@ -131,10 +131,7 @@ public void testGetColumns() throws Exception { } } - private static void checkColumn( - List columns, int columnNumber, String name, - DataType dataType) - throws Exception { + private static void checkColumn(List columns, int columnNumber, String name, DataType dataType) throws Exception { Column column = columns.get(columnNumber); assertEquals(name, column.getName()); assertEquals(dataType, column.getType()); @@ -976,8 +973,7 @@ public void testBrokenIndex() throws Exception { } } - private static void verifyFinderType(Database db, String clazzName) - throws Exception { + private static void verifyFinderType(Database db, String clazzName) throws Exception { java.lang.reflect.Field f = db.getClass().getDeclaredField("_tableFinder"); f.setAccessible(true); Object finder = f.get(db); diff --git a/src/test/java/io/github/spannm/jackcess/TestUtil.java b/src/test/java/io/github/spannm/jackcess/TestUtil.java index 1321e33..75e902a 100644 --- a/src/test/java/io/github/spannm/jackcess/TestUtil.java +++ b/src/test/java/io/github/spannm/jackcess/TestUtil.java @@ -153,10 +153,7 @@ public static Database openCopy(FileFormat fileFormat, File file, return openDB(fileFormat, tmp, false, null, false); } - private static Database openDB( - FileFormat fileFormat, File file, boolean inMem, Charset charset, - boolean readOnly) - throws Exception { + private static Database openDB(FileFormat fileFormat, File file, boolean inMem, Charset charset, boolean readOnly) throws Exception { FileChannel channel = inMem ? MemFileChannel.newChannel( file, MemFileChannel.RW_CHANNEL_MODE) : null; diff --git a/src/test/java/io/github/spannm/jackcess/impl/ExtendedDateTest.java b/src/test/java/io/github/spannm/jackcess/impl/ExtendedDateTest.java index 347b0f8..f741004 100644 --- a/src/test/java/io/github/spannm/jackcess/impl/ExtendedDateTest.java +++ b/src/test/java/io/github/spannm/jackcess/impl/ExtendedDateTest.java @@ -29,11 +29,9 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @@ -47,12 +45,14 @@ public ExtendedDateTest(String name) throws Exception { public void testReadExtendedDate() throws Exception { - DateTimeFormatter dtfNoTime = DateTimeFormatter.ofPattern("M/d/yyy"); - DateTimeFormatter dtfFull = DateTimeFormatter.ofPattern("M/d/yyy h:mm:ss.SSSSSSS a"); + ZoneId zoneId = ZoneId.of("America/New_York"); + DateTimeFormatter dtfNoTime = DateTimeFormatter.ofPattern("M/d/yyy", Locale.US); + DateTimeFormatter dtfFull = DateTimeFormatter.ofPattern("M/d/yyy h:mm:ss.SSSSSSS a", Locale.US); - for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.EXT_DATE)) { + for (TestDB testDB : TestDB.getSupportedForBasename(Basename.EXT_DATE)) { Database db = openMem(testDB); + db.setZoneId(zoneId); Table t = db.getTable("Table1"); for (Row r : t) { diff --git a/src/test/java/io/github/spannm/jackcess/query/QueryTest.java b/src/test/java/io/github/spannm/jackcess/query/QueryTest.java index 84bac78..b3b4d44 100644 --- a/src/test/java/io/github/spannm/jackcess/query/QueryTest.java +++ b/src/test/java/io/github/spannm/jackcess/query/QueryTest.java @@ -26,7 +26,6 @@ import io.github.spannm.jackcess.impl.query.QueryImpl; import io.github.spannm.jackcess.impl.query.QueryImpl.Row; import junit.framework.TestCase; -import org.apache.commons.lang3.StringUtils; import java.util.*; @@ -605,7 +604,7 @@ private static void removeLastRows(Query query, int num) { } private static String multiline(String... strs) { - return StringUtils.join(strs, System.lineSeparator()); + return String.join(System.lineSeparator(), strs); } } diff --git a/src/test/java/io/github/spannm/jackcess/util/StringUtilTest.java b/src/test/java/io/github/spannm/jackcess/util/StringUtilTest.java new file mode 100644 index 0000000..ac7c416 --- /dev/null +++ b/src/test/java/io/github/spannm/jackcess/util/StringUtilTest.java @@ -0,0 +1,84 @@ +package io.github.spannm.jackcess.util; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class StringUtilTest { + + @Test + public void testLength() { + assertEquals(0, StringUtil.length(null)); + assertEquals(0, StringUtil.length("")); + assertEquals(1, StringUtil.length("A")); + assertEquals(1, StringUtil.length(" ")); + assertEquals(4, StringUtil.length("sman")); + } + + @Test + public void testIsEmpty() { + assertTrue(StringUtil.isEmpty(null)); + assertTrue(StringUtil.isEmpty("")); + assertFalse(StringUtil.isEmpty(" ")); + assertFalse(StringUtil.isEmpty("not Empty")); + } + + @Test + public void testIsBlank() { + assertTrue(StringUtil.isBlank(null)); + assertTrue(StringUtil.isBlank("")); + assertTrue(StringUtil.isBlank(" ")); + assertTrue(StringUtil.isBlank(System.lineSeparator())); + } + + @Test + public void testTrimToNull() { + assertNull(StringUtil.trimToNull(null)); + assertNull(StringUtil.trimToNull("")); + assertNull(StringUtil.trimToNull(" ")); + assertEquals("sman", StringUtil.trimToNull("sman")); + assertEquals("81", StringUtil.trimToNull(" 81 ")); + } + + @Test + public void testCapitalize() { + assertNull(StringUtil.capitalize(null)); + assertEquals("", StringUtil.capitalize("")); + assertEquals("Hello", StringUtil.capitalize("hello")); + assertEquals("Foo bar", StringUtil.capitalize("foo bar")); + assertEquals("Boo far", StringUtil.capitalize("Boo far")); + } + + @Test + public void testReplace() { + assertNull(null, StringUtil.replace(null, null, null)); + assertEquals(" ", StringUtil.replace(" ", " ", " ")); + assertEquals("text", StringUtil.replace("text", "", "newText")); + assertEquals(" txt txt ", StringUtil.replace(" text text ", "text", "txt")); + } + + @Test + public void testRemove() { + assertNull(StringUtil.remove(null, null)); + assertNull(StringUtil.remove(null, "")); + assertNull(StringUtil.remove(null, "remove")); + assertEquals("", StringUtil.remove("", "remove")); + assertEquals("input", StringUtil.remove("input", "remove")); + assertEquals("Removed", StringUtil.remove("Removed", "remove")); + assertEquals("", StringUtil.remove("remove", "remove")); + assertEquals("long", StringUtil.remove("long", "longer")); + } + + @Test + public void testReflectionToString() { + assertEquals("null", StringUtil.reflectionToString(null)); + String str = StringUtil.reflectionToString(new TestObj()); + assertTrue(str.matches("^io\\.github\\.spannm\\.jackcess\\.util\\.StringUtilTest\\$TestObj@[0-9a-f]+\\[strVal=testing\\]$")); + assertEquals("Integer[value=47]", StringUtil.reflectionToString(Integer.valueOf(47), false, false)); + } + + static class TestObj { + final String strVal = "testing"; + } + +}