Browse Source

Replace usage of Apache commons-lang3 by compact custom implementations in order to avoid dependency

pull/14/head
Markus Spann 4 months ago
parent
commit
54882b8650
30 changed files with 524 additions and 358 deletions
  1. 0
    5
      pom.xml
  2. 12
    14
      src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java
  3. 5
    3
      src/main/java/com/healthmarketscience/jackcess/impl/CompoundOleUtil.java
  4. 0
    210
      src/main/java/com/healthmarketscience/jackcess/impl/CustomToStringStyle.java
  5. 7
    62
      src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
  6. 9
    8
      src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java
  7. 3
    3
      src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
  8. 3
    3
      src/main/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java
  9. 11
    10
      src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java
  10. 4
    2
      src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java
  11. 2
    1
      src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java
  12. 2
    1
      src/main/java/com/healthmarketscience/jackcess/impl/RelationshipImpl.java
  13. 9
    7
      src/main/java/com/healthmarketscience/jackcess/impl/RowIdImpl.java
  14. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/RowImpl.java
  15. 4
    3
      src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
  16. 3
    1
      src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java
  17. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/complex/ComplexColumnInfoImpl.java
  18. 5
    2
      src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultTextFunctions.java
  19. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java
  20. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
  21. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java
  22. 2
    2
      src/main/java/com/healthmarketscience/jackcess/impl/expr/StringValue.java
  23. 5
    4
      src/main/java/com/healthmarketscience/jackcess/impl/query/QueryImpl.java
  24. 1
    2
      src/main/java/com/healthmarketscience/jackcess/util/ColumnFormatter.java
  25. 1
    2
      src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java
  26. 162
    0
      src/main/java/com/healthmarketscience/jackcess/util/StringUtil.java
  27. 181
    0
      src/main/java/com/healthmarketscience/jackcess/util/ToStringBuilder.java
  28. 2
    1
      src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java
  29. 1
    2
      src/test/java/com/healthmarketscience/jackcess/query/QueryTest.java
  30. 80
    0
      src/test/java/com/healthmarketscience/jackcess/util/StringUtilTest.java

+ 0
- 5
pom.xml View File

</plugins> </plugins>
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
<dependency> <dependency>
<groupId>commons-logging</groupId> <groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId> <artifactId>commons-logging</artifactId>

+ 12
- 14
src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java View File

import com.healthmarketscience.jackcess.impl.expr.NumberFormatter; import com.healthmarketscience.jackcess.impl.expr.NumberFormatter;
import com.healthmarketscience.jackcess.util.ColumnValidator; import com.healthmarketscience.jackcess.util.ColumnValidator;
import com.healthmarketscience.jackcess.util.SimpleColumnValidator; import com.healthmarketscience.jackcess.util.SimpleColumnValidator;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.healthmarketscience.jackcess.util.ToStringBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;




@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.builder(this)
.append("name", "(" + _table.getName() + ") " + _name);
byte typeValue = getOriginalDataType();
sb.append("type", "0x" + Integer.toHexString(typeValue) +
ToStringBuilder sb = ToStringBuilder.builder(this)
.append("name", "(" + _table.getName() + ") " + _name)
.append("type", "0x" + Integer.toHexString(getOriginalDataType()) +
" (" + _type + ")") " (" + _type + ")")
.append("number", _columnNumber) .append("number", _columnNumber)
.append("length", _columnLength) .append("length", _columnLength)
.append("variableLength", _variableLength); .append("variableLength", _variableLength);
if(_calculated) { if(_calculated) {
sb.append("calculated", _calculated) sb.append("calculated", _calculated)
.append("expression",
CustomToStringStyle.ignoreNull(getCalculationContext()));
.appendIgnoreNull("expression", getCalculationContext());
} }
if(_type.isTextual()) { if(_type.isTextual()) {
sb.append("compressedUnicode", isCompressedUnicode()) sb.append("compressedUnicode", isCompressedUnicode())
if(_autoNumber) { if(_autoNumber) {
sb.append("lastAutoNumber", _autoNumberGenerator.getLast()); 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));
sb.appendIgnoreNull("complexInfo", getComplexInfo())
.appendIgnoreNull("validator",
_validator != SimpleColumnValidator.INSTANCE ?
_validator : null)
.appendIgnoreNull("defaultValue", _defValue);
return sb.toString(); return sb.toString();
} }




@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append(null, getBytes()) .append(null, getBytes())
.toString(); .toString();
} }


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append(null, _value + "(" + _version + ")") .append(null, _value + "(" + _version + ")")
.toString(); .toString();
} }

+ 5
- 3
src/main/java/com/healthmarketscience/jackcess/impl/CompoundOleUtil.java View File



import com.healthmarketscience.jackcess.RuntimeIOException; import com.healthmarketscience.jackcess.RuntimeIOException;
import static com.healthmarketscience.jackcess.impl.OleUtil.*; import static com.healthmarketscience.jackcess.impl.OleUtil.*;

import com.healthmarketscience.jackcess.util.MemFileChannel; import com.healthmarketscience.jackcess.util.MemFileChannel;
import com.healthmarketscience.jackcess.util.ToStringBuilder;

import static com.healthmarketscience.jackcess.util.OleBlob.*; import static com.healthmarketscience.jackcess.util.OleBlob.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.poi.poifs.filesystem.DirectoryEntry; import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream; import org.apache.poi.poifs.filesystem.DocumentInputStream;


@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = toString(CustomToStringStyle.builder(this));
ToStringBuilder sb = toString(ToStringBuilder.builder(this));


try { try {
sb.append("hasContentsEntry", hasContentsEntry()); sb.append("hasContentsEntry", hasContentsEntry());


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append("name", _name) .append("name", _name)
.append("length", length()) .append("length", length())
.toString(); .toString();

+ 0
- 210
src/main/java/com/healthmarketscience/jackcess/impl/CustomToStringStyle.java View File

/*
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 com.healthmarketscience.jackcess.impl;

import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang3.builder.StandardToStringStyle;
import org.apache.commons.lang3.builder.ToStringBuilder;

/**
* 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<? extends Map.Entry<?,?>> 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);
}
}

+ 7
- 62
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java View File

import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import com.healthmarketscience.jackcess.ColumnBuilder;
import com.healthmarketscience.jackcess.Cursor;
import com.healthmarketscience.jackcess.CursorBuilder;
import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.DateTimeType;
import com.healthmarketscience.jackcess.Index;
import com.healthmarketscience.jackcess.IndexBuilder;
import com.healthmarketscience.jackcess.IndexCursor;
import com.healthmarketscience.jackcess.PropertyMap;
import com.healthmarketscience.jackcess.Relationship;
import com.healthmarketscience.jackcess.Row;
import com.healthmarketscience.jackcess.RuntimeIOException;
import com.healthmarketscience.jackcess.Table;
import com.healthmarketscience.jackcess.TableBuilder;
import com.healthmarketscience.jackcess.TableDefinition;
import com.healthmarketscience.jackcess.TableMetaData;
import com.healthmarketscience.jackcess.*;
import com.healthmarketscience.jackcess.expr.EvalConfig; import com.healthmarketscience.jackcess.expr.EvalConfig;
import com.healthmarketscience.jackcess.impl.query.QueryImpl; import com.healthmarketscience.jackcess.impl.query.QueryImpl;
import com.healthmarketscience.jackcess.query.Query; import com.healthmarketscience.jackcess.query.Query;
import com.healthmarketscience.jackcess.util.CaseInsensitiveColumnMatcher;
import com.healthmarketscience.jackcess.util.ColumnValidatorFactory;
import com.healthmarketscience.jackcess.util.ErrorHandler;
import com.healthmarketscience.jackcess.util.LinkResolver;
import com.healthmarketscience.jackcess.util.ReadOnlyFileChannel;
import com.healthmarketscience.jackcess.util.SimpleColumnValidatorFactory;
import com.healthmarketscience.jackcess.util.TableIterableBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.healthmarketscience.jackcess.util.*;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;


String accessVersion = (String)getDatabaseProperties().getValue( String accessVersion = (String)getDatabaseProperties().getValue(
PropertyMap.ACCESS_VERSION_PROP); PropertyMap.ACCESS_VERSION_PROP);


if(isBlank(accessVersion)) {
if(StringUtil.isBlank(accessVersion)) {
// no access version, fall back to "generic" // no access version, fall back to "generic"
accessVersion = null; accessVersion = null;
} }
*/ */
private static void validateName(String name, int maxLength, String nameType) private static void validateName(String name, int maxLength, String nameType)
{ {
if(isBlank(name)) {
if(StringUtil.isBlank(name)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
nameType + " must have non-blank name"); nameType + " must have non-blank name");
} }
} }
} }


/**
* 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 @Override
public String toString() { public String toString() {
return ToStringBuilder.reflectionToString(this);
return StringUtil.reflectionToString(this);
} }


/** /**


@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.valueBuilder("TableMetaData")
ToStringBuilder sb = ToStringBuilder.valueBuilder("TableMetaData")
.append("name", getName()); .append("name", getName());
if(isSystem()) { if(isSystem()) {
sb.append("isSystem", isSystem()); sb.append("isSystem", isSystem());

+ 9
- 8
src/main/java/com/healthmarketscience/jackcess/impl/IndexData.java View File

import com.healthmarketscience.jackcess.Index; import com.healthmarketscience.jackcess.Index;
import com.healthmarketscience.jackcess.IndexBuilder; import com.healthmarketscience.jackcess.IndexBuilder;
import com.healthmarketscience.jackcess.RuntimeIOException; import com.healthmarketscience.jackcess.RuntimeIOException;
import com.healthmarketscience.jackcess.util.ToStringBuilder;

import static com.healthmarketscience.jackcess.impl.ByteUtil.ByteStream; import static com.healthmarketscience.jackcess.impl.ByteUtil.ByteStream;
import static com.healthmarketscience.jackcess.impl.IndexCodes.*; import static com.healthmarketscience.jackcess.impl.IndexCodes.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;




@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.builder(this)
ToStringBuilder sb = ToStringBuilder.builder(this)
.append("dataNumber", _number) .append("dataNumber", _number)
.append("pageNumber", _rootPageNumber) .append("pageNumber", _rootPageNumber)
.append("isBackingPrimaryKey", isBackingPrimaryKey()) .append("isBackingPrimaryKey", isBackingPrimaryKey())


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder(this)
return ToStringBuilder.builder(this)
.append("column", getColumn()) .append("column", getColumn())
.append("flags", getFlags() + " " + (isAscending() ? "(ASC)" : "(DSC)")) .append("flags", getFlags() + " " + (isAscending() ? "(ASC)" : "(DSC)"))
.toString(); .toString();
@Override @Override
public String toString() { public String toString() {
return entryBytesToStringBuilder( return entryBytesToStringBuilder(
CustomToStringStyle.valueBuilder(this)
ToStringBuilder.valueBuilder(this)
.append("rowId", _rowId)) .append("rowId", _rowId))
.toString(); .toString();
} }
@Override @Override
public String toString() { public String toString() {
return entryBytesToStringBuilder( return entryBytesToStringBuilder(
CustomToStringStyle.valueBuilder(this)
ToStringBuilder.valueBuilder(this)
.append("rowId", getRowId()) .append("rowId", getRowId())
.append("subPage", _subPageNumber)) .append("subPage", _subPageNumber))
.toString(); .toString();


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append("curPosition", _curPos) .append("curPosition", _curPos)
.append("prevPosition", _prevPos) .append("prevPosition", _prevPos)
.toString(); .toString();


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append("page", _dataPage.getPageNumber()) .append("page", _dataPage.getPageNumber())
.append("idx", _idx) .append("idx", _idx)
.append("entry", _entry) .append("entry", _entry)
(isLeaf() ? "Leaf" : "Node") + "DataPage[" + getPageNumber() + (isLeaf() ? "Leaf" : "Node") + "DataPage[" + getPageNumber() +
"] " + getPrevPageNumber() + ", " + getNextPageNumber() + ", (" + "] " + getPrevPageNumber() + ", " + getNextPageNumber() + ", (" +
getChildTailPageNumber() + ")"; getChildTailPageNumber() + ")";
ToStringBuilder sb = CustomToStringStyle.valueBuilder(objName);
ToStringBuilder sb = ToStringBuilder.valueBuilder(objName);


if((isLeaf() && !entries.isEmpty())) { if((isLeaf() && !entries.isEmpty())) {
sb.append("entryRange", "[" + entries.get(0) + ", " + sb.append("entryRange", "[" + entries.get(0) + ", " +

+ 3
- 3
src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java View File

import com.healthmarketscience.jackcess.CursorBuilder; import com.healthmarketscience.jackcess.CursorBuilder;
import com.healthmarketscience.jackcess.Index; import com.healthmarketscience.jackcess.Index;
import com.healthmarketscience.jackcess.IndexBuilder; import com.healthmarketscience.jackcess.IndexBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.healthmarketscience.jackcess.util.ToStringBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;




@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.builder(this)
ToStringBuilder sb = ToStringBuilder.builder(this)
.append("name", "(" + getTable().getName() + ") " + _name) .append("name", "(" + getTable().getName() + ") " + _name)
.append("number", _indexNumber) .append("number", _indexNumber)
.append("isPrimaryKey", isPrimaryKey()) .append("isPrimaryKey", isPrimaryKey())


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder(this)
return ToStringBuilder.builder(this)
.append("otherIndexNumber", _otherIndexNumber) .append("otherIndexNumber", _otherIndexNumber)
.append("otherTablePageNum", _otherTablePageNumber) .append("otherTablePageNum", _otherTablePageNumber)
.append("isPrimaryTable", isPrimaryTable()) .append("isPrimaryTable", isPrimaryTable())

+ 3
- 3
src/main/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java View File



import static com.healthmarketscience.jackcess.impl.IndexData.*; import static com.healthmarketscience.jackcess.impl.IndexData.*;
import com.healthmarketscience.jackcess.impl.IndexData.DataPage; import com.healthmarketscience.jackcess.impl.IndexData.DataPage;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* Manager of the index pages for a IndexData. * Manager of the index pages for a IndexData.


@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.builder(this);
ToStringBuilder sb = ToStringBuilder.builder(this);
if(_rootPage == null) { if(_rootPage == null) {
sb.append("pages", "(uninitialized)"); sb.append("pages", "(uninitialized)");
} else { } else {


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder("DPExtra")
return ToStringBuilder.builder("DPExtra")
.append(null, _entryView) .append(null, _entryView)
.toString(); .toString();
} }

+ 11
- 10
src/main/java/com/healthmarketscience/jackcess/impl/OleUtil.java View File



import com.healthmarketscience.jackcess.DataType; import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.util.OleBlob; import com.healthmarketscience.jackcess.util.OleBlob;
import com.healthmarketscience.jackcess.util.ToStringBuilder;

import static com.healthmarketscience.jackcess.util.OleBlob.*; import static com.healthmarketscience.jackcess.util.OleBlob.*;
import org.apache.commons.lang3.builder.ToStringBuilder;


/** /**
* Utility code for working with OLE data. * Utility code for working with OLE data.
/** /**
* Creates a new OlBlob instance using the given information. * Creates a new OlBlob instance using the given information.
*/ */
public static OleBlob createBlob(Builder oleBuilder)
public static OleBlob createBlob(OleBlob.Builder oleBuilder)
throws IOException throws IOException
{ {
try { try {
} }
} }


private static byte[] writePackageHeader(Builder oleBuilder,
private static byte[] writePackageHeader(OleBlob.Builder oleBuilder,
long contentLen) { long contentLen) {


byte[] prettyNameBytes = getZeroTermStrBytes(oleBuilder.getPrettyName()); byte[] prettyNameBytes = getZeroTermStrBytes(oleBuilder.getPrettyName());
return headerBytes; return headerBytes;
} }


private static byte[] writePackageStreamHeader(Builder oleBuilder) {
private static byte[] writePackageStreamHeader(OleBlob.Builder oleBuilder) {


byte[] fileNameBytes = getZeroTermStrBytes(oleBuilder.getFileName()); byte[] fileNameBytes = getZeroTermStrBytes(oleBuilder.getFileName());
byte[] filePathBytes = getZeroTermStrBytes(oleBuilder.getFilePath()); byte[] filePathBytes = getZeroTermStrBytes(oleBuilder.getFilePath());
return headerBytes; return headerBytes;
} }


private static byte[] writePackageStreamFooter(Builder oleBuilder) {
private static byte[] writePackageStreamFooter(OleBlob.Builder oleBuilder) {


// note, these are _not_ zero terminated // note, these are _not_ zero terminated
byte[] fileNameBytes = oleBuilder.getFileName().getBytes(OLE_UTF_CHARSET); byte[] fileNameBytes = oleBuilder.getFileName().getBytes(OLE_UTF_CHARSET);


@Override @Override
public String toString() { public String toString() {
ToStringBuilder sb = CustomToStringStyle.builder(this);
ToStringBuilder sb = ToStringBuilder.builder(this);
if(_content != null) { if(_content != null) {
sb.append("content", _content); sb.append("content", _content);
} else { } else {


@Override @Override
public String toString() { public String toString() {
return toString(CustomToStringStyle.builder(this))
return toString(ToStringBuilder.builder(this))
.append("fileName", _fileName) .append("fileName", _fileName)
.append("linkPath", _linkPath) .append("linkPath", _linkPath)
.append("filePath", _filePath) .append("filePath", _filePath)


@Override @Override
public String toString() { public String toString() {
return toString(CustomToStringStyle.builder(this))
return toString(ToStringBuilder.builder(this))
.append("fileName", _fileName) .append("fileName", _fileName)
.append("filePath", _filePath) .append("filePath", _filePath)
.append("localFilePath", _localFilePath) .append("localFilePath", _localFilePath)


@Override @Override
public String toString() { public String toString() {
return toString(CustomToStringStyle.builder(this))
return toString(ToStringBuilder.builder(this))
.toString(); .toString();
} }
} }


@Override @Override
public String toString() { public String toString() {
return toString(CustomToStringStyle.builder(this))
return toString(ToStringBuilder.builder(this))
.append("content", _blob._bytes) .append("content", _blob._bytes)
.toString(); .toString();
} }

+ 4
- 2
src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java View File



import com.healthmarketscience.jackcess.DataType; import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.PropertyMap; import com.healthmarketscience.jackcess.PropertyMap;
import com.healthmarketscience.jackcess.util.StringUtil;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* Collection of PropertyMap instances read from a single property data block. * Collection of PropertyMap instances read from a single property data block.


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder(this)
return ToStringBuilder.builder(this)
.append(null, _maps.values()) .append(null, _maps.values())
.toString(); .toString();
} }
public static String getTrimmedStringProperty( public static String getTrimmedStringProperty(
PropertyMap props, String propName) PropertyMap props, String propName)
{ {
return DatabaseImpl.trimToNull((String)props.getValue(propName));
return StringUtil.trimToNull((String)props.getValue(propName));
} }


/** /**

+ 2
- 1
src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java View File

import com.healthmarketscience.jackcess.IndexCursor; import com.healthmarketscience.jackcess.IndexCursor;
import com.healthmarketscience.jackcess.RelationshipBuilder; import com.healthmarketscience.jackcess.RelationshipBuilder;
import com.healthmarketscience.jackcess.Row; import com.healthmarketscience.jackcess.Row;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* Helper class used to maintain state during relationship creation. * Helper class used to maintain state during relationship creation.
colNames = getColumnNames(cols); colNames = getColumnNames(cols);
} }


return CustomToStringStyle.valueBuilder(tableName)
return ToStringBuilder.valueBuilder(tableName)
.append(null, colNames) .append(null, colNames)
.toString(); .toString();
} }

+ 2
- 1
src/main/java/com/healthmarketscience/jackcess/impl/RelationshipImpl.java View File

import com.healthmarketscience.jackcess.Column; import com.healthmarketscience.jackcess.Column;
import com.healthmarketscience.jackcess.Relationship; import com.healthmarketscience.jackcess.Relationship;
import com.healthmarketscience.jackcess.Table; import com.healthmarketscience.jackcess.Table;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* Information about a relationship between two tables in the database. * Information about a relationship between two tables in the database.


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder(this)
return ToStringBuilder.builder(this)
.append("name", _name) .append("name", _name)
.append("fromTable", _fromTable.getName()) .append("fromTable", _fromTable.getName())
.append("fromColumns", _fromColumns) .append("fromColumns", _fromColumns)

+ 9
- 7
src/main/java/com/healthmarketscience/jackcess/impl/RowIdImpl.java View File

import java.io.Serializable; import java.io.Serializable;


import com.healthmarketscience.jackcess.RowId; import com.healthmarketscience.jackcess.RowId;
import org.apache.commons.lang3.builder.CompareToBuilder;




/** /**
public int compareTo(RowId other) { public int compareTo(RowId other) {
return compareTo((RowIdImpl)other); return compareTo((RowIdImpl)other);
} }
public int compareTo(RowIdImpl 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 @Override

+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/RowImpl.java View File

import com.healthmarketscience.jackcess.Row; import com.healthmarketscience.jackcess.Row;
import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey; import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey;
import com.healthmarketscience.jackcess.util.OleBlob; import com.healthmarketscience.jackcess.util.OleBlob;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* A row of data as column-&gt;value pairs. * A row of data as column-&gt;value pairs.


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder("Row[" + _id + "]")
return ToStringBuilder.valueBuilder("Row[" + _id + "]")
.append(null, this) .append(null, this)
.toString(); .toString();
} }

+ 4
- 3
src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java View File

import com.healthmarketscience.jackcess.expr.Identifier; import com.healthmarketscience.jackcess.expr.Identifier;
import com.healthmarketscience.jackcess.util.ErrorHandler; import com.healthmarketscience.jackcess.util.ErrorHandler;
import com.healthmarketscience.jackcess.util.ExportUtil; import com.healthmarketscience.jackcess.util.ExportUtil;
import com.healthmarketscience.jackcess.util.ToStringBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;




@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.builder(this)
return ToStringBuilder.builder(this)
.append("type", (_tableType + (!isSystem() ? " (USER)" : " (SYSTEM)"))) .append("type", (_tableType + (!isSystem() ? " (USER)" : " (SYSTEM)")))
.append("name", _name) .append("name", _name)
.append("rowCount", _rowCount) .append("rowCount", _rowCount)
.append("columnCount", _columns.size()) .append("columnCount", _columns.size())
.append("indexCount(data)", _indexCount) .append("indexCount(data)", _indexCount)
.append("logicalIndexCount", _logicalIndexCount) .append("logicalIndexCount", _logicalIndexCount)
.append("validator", CustomToStringStyle.ignoreNull(_rowValidator))
.appendIgnoreNull("validator", _rowValidator)
.append("columns", _columns) .append("columns", _columns)
.append("indexes", _indexes) .append("indexes", _indexes)
.append("ownedPages", _ownedPages) .append("ownedPages", _ownedPages)


@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append("headerRowId", _headerRowId) .append("headerRowId", _headerRowId)
.append("finalRowId", _finalRowId) .append("finalRowId", _finalRowId)
.toString(); .toString();

+ 3
- 1
src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java View File

import java.util.BitSet; import java.util.BitSet;
import java.util.List; import java.util.List;


import com.healthmarketscience.jackcess.util.ToStringBuilder;



/** /**
* Describes which database pages a particular table uses * Describes which database pages a particular table uses
rangeToString(ranges, curRangeStart, prevPage); rangeToString(ranges, curRangeStart, prevPage);
} }


return CustomToStringStyle.valueBuilder(
return ToStringBuilder.valueBuilder(
_handler.getClass().getSimpleName()) _handler.getClass().getSimpleName())
.append("range", "(" + _startPage + "-" + _endPage + ")") .append("range", "(" + _startPage + "-" + _endPage + ")")
.append("pageNumbers", ranges) .append("pageNumbers", ranges)

+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/complex/ComplexColumnInfoImpl.java View File

import com.healthmarketscience.jackcess.complex.ComplexValue; import com.healthmarketscience.jackcess.complex.ComplexValue;
import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey; import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey;
import com.healthmarketscience.jackcess.impl.ColumnImpl; import com.healthmarketscience.jackcess.impl.ColumnImpl;
import com.healthmarketscience.jackcess.impl.CustomToStringStyle;
import com.healthmarketscience.jackcess.impl.TableImpl; import com.healthmarketscience.jackcess.impl.TableImpl;
import com.healthmarketscience.jackcess.util.ToStringBuilder;


/** /**
* Base class for the additional information tracked for complex columns. * Base class for the additional information tracked for complex columns.
@Override @Override
public String toString() { public String toString() {
return CustomToStringStyle.valueBuilder(this)
return ToStringBuilder.valueBuilder(this)
.append("complexType", getType()) .append("complexType", getType())
.append("complexTypeId", _complexTypeId) .append("complexTypeId", _complexTypeId)
.toString(); .toString();

+ 5
- 2
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultTextFunctions.java View File

package com.healthmarketscience.jackcess.impl.expr; package com.healthmarketscience.jackcess.impl.expr;


import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Arrays;
import java.util.stream.Collectors;


import com.healthmarketscience.jackcess.expr.EvalContext; import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.EvalException; import com.healthmarketscience.jackcess.expr.EvalException;
import com.healthmarketscience.jackcess.expr.Function; import com.healthmarketscience.jackcess.expr.Function;
import com.healthmarketscience.jackcess.expr.LocaleContext; import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.util.StringUtil;
import static com.healthmarketscience.jackcess.impl.expr.DefaultFunctions.*; import static com.healthmarketscience.jackcess.impl.expr.DefaultFunctions.*;
import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*; import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*;


break; break;
case 3: case 3:
// vbProperCase // vbProperCase
str = org.apache.commons.lang3.text.WordUtils.capitalize(
str.toLowerCase());
str = Arrays.stream(str.toLowerCase().split(" "))
.map(StringUtil::capitalize).collect(Collectors.joining(" "));
break; break;
default: default:
// do nothing // do nothing

+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java View File

import com.healthmarketscience.jackcess.expr.TemporalConfig; import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.ColumnImpl; import com.healthmarketscience.jackcess.impl.ColumnImpl;
import org.apache.commons.lang3.StringUtils;
import com.healthmarketscience.jackcess.util.StringUtil;




/** /**
exprStr = exprStr.trim(); exprStr = exprStr.trim();
} }


if(StringUtils.isEmpty(exprStr)) {
if(StringUtil.isEmpty(exprStr)) {
return null; return null;
} }



+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java View File

import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token; import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType; import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType;
import org.apache.commons.lang3.StringUtils;
import com.healthmarketscience.jackcess.util.StringUtil;




/** /**


private static void literalStrToString(String str, StringBuilder sb) { private static void literalStrToString(String str, StringBuilder sb) {
sb.append("\"") sb.append("\"")
.append(StringUtils.replace(str, "\"", "\"\""))
.append(StringUtil.replace(str, "\"", "\"\""))
.append("\""); .append("\"");
} }



+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/expr/FormatUtil.java View File

import com.healthmarketscience.jackcess.expr.NumericConfig; import com.healthmarketscience.jackcess.expr.NumericConfig;
import com.healthmarketscience.jackcess.expr.TemporalConfig; import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.expr.Value;
import org.apache.commons.lang3.StringUtils;
import com.healthmarketscience.jackcess.util.StringUtil;
import static com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.ExprBuf; import static com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.ExprBuf;


/** /**
return predefFmt; return predefFmt;
} }


if(StringUtils.isEmpty(fmtStr)) {
if(StringUtil.isEmpty(fmtStr)) {
return DUMMY_FMT; return DUMMY_FMT;
} }



+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/impl/expr/StringValue.java View File

import com.healthmarketscience.jackcess.expr.EvalException; import com.healthmarketscience.jackcess.expr.EvalException;
import com.healthmarketscience.jackcess.expr.LocaleContext; import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.expr.Value;
import org.apache.commons.lang3.StringUtils;
import com.healthmarketscience.jackcess.util.StringUtil;


/** /**
* *
// - convert decimal separator to '.' // - convert decimal separator to '.'
DecimalFormatSymbols syms = ctx.getNumericConfig().getDecimalFormatSymbols(); DecimalFormatSymbols syms = ctx.getNumericConfig().getDecimalFormatSymbols();
char groupSepChar = syms.getGroupingSeparator(); char groupSepChar = syms.getGroupingSeparator();
tmpVal = StringUtils.remove(tmpVal, groupSepChar);
tmpVal = StringUtil.remove(tmpVal, String.valueOf(groupSepChar));


char decSepChar = syms.getDecimalSeparator(); char decSepChar = syms.getDecimalSeparator();
if((decSepChar != ValueSupport.CANON_DEC_SEP) && (tmpVal.indexOf(decSepChar) >= 0)) { if((decSepChar != ValueSupport.CANON_DEC_SEP) && (tmpVal.indexOf(decSepChar) >= 0)) {

+ 5
- 4
src/main/java/com/healthmarketscience/jackcess/impl/query/QueryImpl.java View File

import com.healthmarketscience.jackcess.impl.DatabaseImpl; import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import com.healthmarketscience.jackcess.impl.RowIdImpl; import com.healthmarketscience.jackcess.impl.RowIdImpl;
import com.healthmarketscience.jackcess.impl.RowImpl; import com.healthmarketscience.jackcess.impl.RowImpl;
import static com.healthmarketscience.jackcess.impl.query.QueryFormat.*;
import com.healthmarketscience.jackcess.query.Query; import com.healthmarketscience.jackcess.query.Query;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.healthmarketscience.jackcess.util.StringUtil;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;


import static com.healthmarketscience.jackcess.impl.query.QueryFormat.*;



/** /**
* Base class for classes which encapsulate information about an Access query. * Base class for classes which encapsulate information about an Access query.


@Override @Override
public String toString() { public String toString() {
return ToStringBuilder.reflectionToString(this);
return StringUtil.reflectionToString(this);
} }


/** /**


@Override @Override
public String toString() { public String toString() {
return ToStringBuilder.reflectionToString(this);
return StringUtil.reflectionToString(this);
} }
} }



+ 1
- 2
src/main/java/com/healthmarketscience/jackcess/util/ColumnFormatter.java View File

import com.healthmarketscience.jackcess.impl.ColEvalContext; import com.healthmarketscience.jackcess.impl.ColEvalContext;
import com.healthmarketscience.jackcess.impl.ColumnImpl; import com.healthmarketscience.jackcess.impl.ColumnImpl;
import com.healthmarketscience.jackcess.impl.expr.FormatUtil; import com.healthmarketscience.jackcess.impl.expr.FormatUtil;
import org.apache.commons.lang3.StringUtils;


/** /**
* Utility for applying Column formatting to column values for display. This * Utility for applying Column formatting to column values for display. This
*/ */
public void setFormatString(String fmtStr) throws IOException { public void setFormatString(String fmtStr) throws IOException {
PropertyMap props = _col.getProperties(); PropertyMap props = _col.getProperties();
if(!StringUtils.isEmpty(fmtStr)) {
if(!StringUtil.isEmpty(fmtStr)) {
props.put(PropertyMap.FORMAT_PROP, fmtStr); props.put(PropertyMap.FORMAT_PROP, fmtStr);
} else { } else {
props.remove(PropertyMap.FORMAT_PROP); props.remove(PropertyMap.FORMAT_PROP);

+ 1
- 2
src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java View File

import com.healthmarketscience.jackcess.Table; import com.healthmarketscience.jackcess.Table;
import com.healthmarketscience.jackcess.TableBuilder; import com.healthmarketscience.jackcess.TableBuilder;
import com.healthmarketscience.jackcess.impl.ByteUtil; import com.healthmarketscience.jackcess.impl.ByteUtil;
import com.healthmarketscience.jackcess.impl.DatabaseImpl;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
throws IOException throws IOException
{ {
String line = in.readLine(); String line = in.readLine();
if(DatabaseImpl.isBlank(line)) {
if(StringUtil.isBlank(line)) {
return null; return null;
} }



+ 162
- 0
src/main/java/com/healthmarketscience/jackcess/util/StringUtil.java View File

package com.healthmarketscience.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;

/**
* <p>
* Static utility methods for null-safe {@link String} operations.
* </p>
*
* 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 -> {
f.setAccessible(true);
if (!firstField.compareAndSet(true, false)) {
sb.append(',');
}
sb.append(f.getName()).append('=');
try {
Object val = f.get(obj);
sb.append(val == null ? "<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.<br>
*
* @param obj object to generate string from
* @return string representation
*/
public static String reflectionToString(Object obj) {
return reflectionToString(obj, true, true);
}

}

+ 181
- 0
src/main/java/com/healthmarketscience/jackcess/util/ToStringBuilder.java View File

package com.healthmarketscience.jackcess.util;

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;

import com.healthmarketscience.jackcess.impl.ByteUtil;
import com.healthmarketscience.jackcess.impl.PageChannel;

/**
* <p>Builder for {@link Object#toString()} methods.</p>
*
* @author Markus Spann
*/
public class ToStringBuilder
{
/** Object registry for avoidance of cycles. */
private static final Map<Object, Object> 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 = "<null>";
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);
}
}
}

}

+ 2
- 1
src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java View File

RowImpl row = new RowImpl(new RowIdImpl(1, 1)); RowImpl row = new RowImpl(new RowIdImpl(1, 1));
row.put("id", 37); row.put("id", 37);
row.put("data", null); row.put("data", null);
assertEquals("Row[1:1][{id=37,data=<null>}]", row.toString());
String str = row.toString();
assertEquals("Row[1:1][{id=37,data=<null>}]", str);
} }


public void testIterateTableNames() throws Exception { public void testIterateTableNames() throws Exception {

+ 1
- 2
src/test/java/com/healthmarketscience/jackcess/query/QueryTest.java View File

import com.healthmarketscience.jackcess.impl.query.QueryImpl; import com.healthmarketscience.jackcess.impl.query.QueryImpl;
import com.healthmarketscience.jackcess.impl.query.QueryImpl.Row; import com.healthmarketscience.jackcess.impl.query.QueryImpl.Row;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.commons.lang3.StringUtils;


import static com.healthmarketscience.jackcess.impl.query.QueryFormat.*; import static com.healthmarketscience.jackcess.impl.query.QueryFormat.*;




private static String multiline(String... strs) private static String multiline(String... strs)
{ {
return StringUtils.join(strs, System.lineSeparator());
return String.join(System.lineSeparator(), strs);
} }


} }

+ 80
- 0
src/test/java/com/healthmarketscience/jackcess/util/StringUtilTest.java View File

package com.healthmarketscience.jackcess.util;

import org.junit.Test;

import static org.junit.Assert.*;

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));
assertTrue(StringUtil.reflectionToString("").matches("^java\\.lang\\.String@[0-9a-f]+\\[hash=0,value=\\[C.+$"));
assertEquals("Integer[value=47]", StringUtil.reflectionToString(Integer.valueOf(47), false, false));
}

}

Loading…
Cancel
Save