From 7017786a82b70306d01693f078d949d10941ac09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Suszy=C5=84ski?= Date: Thu, 4 Jul 2019 19:36:25 +0200 Subject: [PATCH 1/3] (feat) configuration using Java's service loader Additional rewrite of library. fixes issue #7 --- .gitignore | 122 +++++++++- .mvn/wrapper/MavenWrapperDownloader.java | 51 ++-- .mvn/wrapper/maven-wrapper.properties | 19 +- .travis.yml | 23 +- LICENSE | 2 +- mvnw | 32 ++- mvnw.cmd | 37 ++- pom.xml | 104 +++++--- .../utils/stringify/ObjectStringifier.java | 44 ---- .../utils/stringify/Stringify.java | 65 +++++ .../stringify/api/AlwaysTruePredicate.java | 31 +++ .../utils/stringify/api/Configuration.java | 57 +++++ .../{configuration => api}/DisplayNull.java | 18 +- .../{configuration => api}/DoNotInspect.java | 21 +- .../{configuration => api}/Inspect.java | 21 +- .../utils/stringify/api/InspectionPoint.java | 47 ++++ .../utils/stringify/api/Mode.java | 32 +++ .../utils/stringify/api/package-info.java | 26 ++ .../configuration/AlwaysTruePredicate.java | 14 -- .../stringify/configuration/BeanFactory.java | 9 - .../configuration/InspectionPoint.java | 32 --- .../utils/stringify/configuration/Mode.java | 16 -- .../stringify/configuration/package-info.java | 8 - .../stringify/impl/BeanFactoryCache.java | 62 +++++ .../stringify/impl/BootAwareBootFactory.java | 67 ++++++ .../stringify/impl/CharSequenceInspector.java | 20 +- .../stringify/impl/CharacterInspector.java | 20 +- .../utils/stringify/impl/ClassLocator.java | 18 +- .../stringify/impl/DefaultBeanFactory.java | 32 +++ .../stringify/impl/DefaultConfiguration.java | 60 +++++ .../impl/DefaultConfigurationLoader.java | 40 +++ .../impl/DefaultInspectionContext.java | 48 ++++ .../stringify/impl/DefaultStringify.java | 87 +++++++ .../stringify/impl/FallbackBootFactory.java | 39 +++ .../utils/stringify/impl/Function.java | 9 - .../stringify/impl/HibernateLazyChecker.java | 31 ++- .../stringify/impl/InspectFieldPredicate.java | 18 +- .../utils/stringify/impl/Inspectable.java | 5 + .../utils/stringify/impl/InspectingField.java | 16 ++ .../impl/InspectingFieldFactory.java | 28 ++- .../stringify/impl/InspectingFieldImpl.java | 22 +- .../stringify/impl/InspectionContext.java | 26 ++ .../stringify/impl/InspectionPointImpl.java | 49 ++-- .../utils/stringify/impl/InspectionUtils.java | 14 ++ .../utils/stringify/impl/Inspector.java | 169 +++++++++++++ .../stringify/impl/IterableInspector.java | 20 +- .../utils/stringify/impl/JPALazyChecker.java | 15 -- .../stringify/impl/JPALazyCheckerFacade.java | 40 --- .../stringify/impl/JPALazyInspector.java | 20 -- .../utils/stringify/impl/JpaLazyChecker.java | 31 +++ .../stringify/impl/JpaLazyCheckerFacade.java | 51 ++++ .../stringify/impl/JpaLazyInspector.java | 38 +++ .../utils/stringify/impl/MapInspector.java | 19 +- .../utils/stringify/impl/ObjectInspector.java | 27 ++- .../stringify/impl/PrimitiveInspector.java | 19 +- .../PromiscuousInspectFieldPredicate.java | 29 ++- .../impl/QuietInspectFieldPredicate.java | 27 ++- .../stringify/impl/RecursionInspector.java | 22 +- .../stringify/impl/ReflectionBeanFactory.java | 64 +++-- .../utils/stringify/impl/State.java | 10 - .../stringify/impl/ToStringResolver.java | 41 ++-- .../impl/ToStringResolverFactory.java | 9 - .../impl/ToStringResolverFactoryImpl.java | 12 - .../stringify/impl/ToStringResolverImpl.java | 227 +++++------------- .../utils/stringify/impl/package-info.java | 20 +- .../utils/stringify/lang/Predicate.java | 23 -- .../utils/stringify/lang/Supplier.java | 24 -- .../utils/stringify/lang/package-info.java | 8 - .../utils/stringify/package-info.java | 23 +- .../utils/stringify/spi/BeanFactory.java | 38 +++ .../utils/stringify/spi/BootingAware.java | 33 +++ .../utils/stringify/spi/Configurator.java | 45 ++++ .../utils/stringify/spi/package-info.java | 27 +++ .../wavesoftware/utils/stringify/Account.java | 16 ++ .../pl/wavesoftware/utils/stringify/Acme.java | 12 + .../wavesoftware/utils/stringify/Earth.java | 20 +- .../utils/stringify/IsInDevelopment.java | 21 +- .../pl/wavesoftware/utils/stringify/Moon.java | 20 +- .../wavesoftware/utils/stringify/Person.java | 22 +- .../wavesoftware/utils/stringify/Phase.java | 18 +- .../wavesoftware/utils/stringify/Planet.java | 24 +- .../utils/stringify/PlanetSystem.java | 20 +- .../stringify/ProductionEnvironment.java | 21 +- .../utils/stringify/SimpleUser.java | 18 +- ...ectStringifierIT.java => StringifyIT.java} | 44 ++-- ...tringifierTest.java => StringifyTest.java} | 166 ++++++++----- .../utils/stringify/TestBeanFactory.java | 21 ++ .../utils/stringify/TestRepository.java | 16 ++ .../utils/stringify/TestingConfigurator.java | 13 + .../utils/stringify/UnlessContainsSecret.java | 13 + .../pl/wavesoftware/utils/stringify/User.java | 18 +- .../impl/InspectionPointImplTest.java | 24 +- ...esoftware.utils.stringify.spi.Configurator | 1 + src/test/resources/simplelogger.properties | 5 - 94 files changed, 2434 insertions(+), 772 deletions(-) mode change 100755 => 100644 .mvn/wrapper/MavenWrapperDownloader.java mode change 100755 => 100644 .mvn/wrapper/maven-wrapper.properties mode change 100755 => 100644 mvnw.cmd mode change 100644 => 100755 pom.xml delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/ObjectStringifier.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/Stringify.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/api/AlwaysTruePredicate.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java rename src/main/java/pl/wavesoftware/utils/stringify/{configuration => api}/DisplayNull.java (50%) rename src/main/java/pl/wavesoftware/utils/stringify/{configuration => api}/DoNotInspect.java (54%) rename src/main/java/pl/wavesoftware/utils/stringify/{configuration => api}/Inspect.java (54%) mode change 100644 => 100755 create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/api/InspectionPoint.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/api/Mode.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/api/package-info.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/configuration/AlwaysTruePredicate.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/configuration/BeanFactory.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/configuration/InspectionPoint.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/configuration/Mode.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/configuration/package-info.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/BeanFactoryCache.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/BootAwareBootFactory.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultBeanFactory.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfiguration.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfigurationLoader.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultInspectionContext.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultStringify.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/FallbackBootFactory.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/Function.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/Inspectable.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionContext.java create mode 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionUtils.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/Inspector.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyChecker.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyCheckerFacade.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyInspector.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyChecker.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyCheckerFacade.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyInspector.java mode change 100644 => 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/ReflectionBeanFactory.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/State.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactory.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactoryImpl.java mode change 100644 => 100755 src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverImpl.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/lang/Predicate.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/lang/Supplier.java delete mode 100644 src/main/java/pl/wavesoftware/utils/stringify/lang/package-info.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/spi/BeanFactory.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/spi/BootingAware.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java create mode 100644 src/main/java/pl/wavesoftware/utils/stringify/spi/package-info.java create mode 100755 src/test/java/pl/wavesoftware/utils/stringify/Acme.java rename src/test/java/pl/wavesoftware/utils/stringify/{ObjectStringifierIT.java => StringifyIT.java} (73%) mode change 100644 => 100755 rename src/test/java/pl/wavesoftware/utils/stringify/{ObjectStringifierTest.java => StringifyTest.java} (54%) mode change 100644 => 100755 create mode 100755 src/test/java/pl/wavesoftware/utils/stringify/TestBeanFactory.java create mode 100755 src/test/java/pl/wavesoftware/utils/stringify/TestingConfigurator.java create mode 100755 src/test/java/pl/wavesoftware/utils/stringify/UnlessContainsSecret.java create mode 100755 src/test/resources/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator delete mode 100644 src/test/resources/simplelogger.properties diff --git a/.gitignore b/.gitignore index a8c37fb..f5dddf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,120 @@ -target -.idea -*.jar +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +### NetBeans template +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml +.nb-gradle/ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + *.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +### Eclipse template +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse + diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java old mode 100755 new mode 100644 index d475a89..c32394f --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -1,22 +1,18 @@ /* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - + * Copyright 2007-present the original author or authors. + * + * 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. + */ import java.net.*; import java.io.*; import java.nio.channels.*; @@ -24,11 +20,12 @@ Licensed to the Apache Software Foundation (ASF) under one public class MavenWrapperDownloader { + private static final String WRAPPER_VERSION = "0.5.5"; /** * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar"; + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; /** * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to @@ -76,13 +73,13 @@ public static void main(String args[]) { } } } - System.out.println("- Downloading from: : " + url); + System.out.println("- Downloading from: " + url); File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); if(!outputFile.getParentFile().exists()) { if(!outputFile.getParentFile().mkdirs()) { System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); } } System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); @@ -98,6 +95,16 @@ public static void main(String args[]) { } private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } URL website = new URL(urlString); ReadableByteChannel rbc; rbc = Channels.newChannel(website.openStream()); diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index a5fcc11..6fa5527 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,18 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip \ No newline at end of file +# +# Copyright 2018-2019 Wave Software +# +# 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. +# + +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar diff --git a/.travis.yml b/.travis.yml index 7c0de99..3fe6a0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,16 @@ language: java -script: ./mvnw install --fail-at-end +sudo: false +dist: xenial +script: ./mvnw -V clean verify --fail-at-end -U -Prelease-checks matrix: include: - - jdk: openjdk7 - - jdk: openjdk8 - env: JACOCO=true COVERALLS=true - - jdk: oraclejdk8 - - jdk: oraclejdk9 - - jdk: openjdk8 - env: GDMSESSION=sonar - - jdk: openjdk8 - env: SONAR=publish + - jdk: openjdk8 + env: JACOCO=true COVERALLS=true + - jdk: openjdk11 + env: JACOCO=true + - jdk: openjdk8 + env: JACOCO=true SONAR=publish + script: ./mvnw -V clean verify sonar:sonar --fail-at-end -U +notifications: + email: + on_failure: change diff --git a/LICENSE b/LICENSE index 78e0362..6afd9d3 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Wave Software + Copyright 2018-2019 Wave Software Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/mvnw b/mvnw index 961a825..d2f0ea3 100755 --- a/mvnw +++ b/mvnw @@ -114,7 +114,6 @@ if $mingw ; then M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? fi if [ -z "$JAVA_HOME" ]; then @@ -212,7 +211,11 @@ else if [ "$MVNW_VERBOSE" = true ]; then echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + fi while IFS="=" read key value; do case "$key" in (wrapperUrl) jarUrl="$value"; break ;; esac @@ -221,22 +224,38 @@ else echo "Downloading from: $jarUrl" fi wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi if command -v wget > /dev/null; then if [ "$MVNW_VERBOSE" = true ]; then echo "Found wget ... using wget" fi - wget "$jarUrl" -O "$wrapperJarPath" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi elif command -v curl > /dev/null; then if [ "$MVNW_VERBOSE" = true ]; then echo "Found curl ... using curl" fi - curl -o "$wrapperJarPath" "$jarUrl" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + else if [ "$MVNW_VERBOSE" = true ]; then echo "Falling back to using Java to download" fi javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi if [ -e "$javaClass" ]; then if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then if [ "$MVNW_VERBOSE" = true ]; then @@ -277,6 +296,11 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index 183eb47..b26ab24 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -37,7 +37,7 @@ @echo off @REM set title of command window title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% @REM set %HOME% to equivalent of $HOME @@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B ) @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central @REM This allows using the maven wrapper in projects that prohibit checking in binary data. if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) ) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) ) @REM End of extension +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end diff --git a/pom.xml b/pom.xml old mode 100644 new mode 100755 index a247eed..252dc63 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,20 @@ + + 4.0.0 @@ -67,11 +83,11 @@ ${project.build.directory}/sonar https://sonar.wavesoftware.pl jacoco - 7 + 8 ${java.source.version} 1.${java.source.version} ${maven.compiler.source} - 0.8.1 + 0.8.4 ${skipTests} @@ -80,60 +96,54 @@ - - pl.wavesoftware - eid-exceptions - 1.2.0 - org.projectlombok lombok - 1.16.20 + 1.18.8 provided true + + pl.wavesoftware + eid-exceptions + 2.0.0 + + + org.slf4j + slf4j-api + 1.7.26 + - junit - junit - 4.12 + pl.wavesoftware.testing + junit5-starter + 1.0.0 + pom test org.hibernate hibernate-core - 5.0.11.Final + 5.4.3.Final test true org.openjdk.jmh jmh-core - 1.20 + 1.21 test org.openjdk.jmh jmh-generator-annprocess - 1.20 - test - - - org.slf4j - slf4j-simple - 1.7.25 - test - - - org.assertj - assertj-core - 2.5.0 + 1.21 test pl.wavesoftware jmh-junit-utilities - 1.0.0 + 2.0.0 test @@ -144,7 +154,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.4.0.905 + 3.6.0.1398 com.manamind.jgitflow @@ -186,23 +196,23 @@ maven-compiler-plugin - 3.7.0 + 3.8.1 true - -Xlint:all + -Xlint:all,-processing maven-jar-plugin - 3.1.0 + 3.1.2 maven-surefire-plugin - 2.21.0 + 2.22.2 false @@ -210,7 +220,7 @@ maven-failsafe-plugin - 2.21.0 + 2.22.2 false @@ -231,7 +241,7 @@ maven-source-plugin - 3.0.1 + 3.1.0 attach-sources @@ -243,7 +253,7 @@ maven-javadoc-plugin - 3.0.0 + 3.1.0 attach-javadocs @@ -276,11 +286,11 @@ maven-resources-plugin - 3.0.2 + 3.1.0 maven-site-plugin - 3.7 + 3.7.1 @@ -460,6 +470,26 @@ + + + release-checks + + + performRelease + true + + + + + + maven-source-plugin + + + maven-javadoc-plugin + + + + diff --git a/src/main/java/pl/wavesoftware/utils/stringify/ObjectStringifier.java b/src/main/java/pl/wavesoftware/utils/stringify/ObjectStringifier.java deleted file mode 100644 index 650d90d..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/ObjectStringifier.java +++ /dev/null @@ -1,44 +0,0 @@ -package pl.wavesoftware.utils.stringify; - -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; -import pl.wavesoftware.utils.stringify.configuration.Inspect; -import pl.wavesoftware.utils.stringify.configuration.Mode; -import pl.wavesoftware.utils.stringify.impl.ToStringResolver; -import pl.wavesoftware.utils.stringify.impl.ToStringResolverFactory; -import pl.wavesoftware.utils.stringify.impl.ToStringResolverFactoryImpl; - -/** - * @author Krzysztof Suszyński - * @since 2018-04-18 - */ -@Setter -@RequiredArgsConstructor -public final class ObjectStringifier { - private static final ToStringResolverFactory RESOLVER_FACTORY = - new ToStringResolverFactoryImpl(); - private final Object target; - private Mode mode = Mode.DEFAULT_MODE; - private BeanFactory beanFactory; - - /** - * Creates string representation of given object using {@link Inspect} on given fields. - * - * @return a string representation of given object - */ - public CharSequence stringify() { - ToStringResolver resolver = RESOLVER_FACTORY - .create(target) - .withMode(mode); - if (beanFactory != null) { - resolver = resolver.withBeanFactory(beanFactory); - } - return resolver.resolve(); - } - - @Override - public String toString() { - return stringify().toString(); - } -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java b/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java new file mode 100755 index 0000000..b1aeed4 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; + +import pl.wavesoftware.utils.stringify.api.Configuration; +import pl.wavesoftware.utils.stringify.api.Inspect; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.impl.DefaultStringify; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +/** + * A utility to safely inspect any Java Object as String representation. It's best to be + * used with domain model (also with JPA entities) with intention to dump those entities + * as text to log files. + *

+ * It runs in two modes: {@code PROMISCUOUS} (by default) and {@code QUIET}. In + * {@code PROMISCUOUS} mode every defined field is automatically inspected, unless the + * field is annotated with {@code @DoNotInspect} annotation. In {@code QUIET} mode only + * fields annotated with @Inspect will gets inspected. + *

+ * This library has proper support for object graph cycles, and JPA (Hibernate) + * lazy loaded elements. + * + * @author Krzysztof Suszynski + * @since 1.0.0 + */ +public interface Stringify extends Configuration, CharSequence { + + /** + * Creates string representation of given object using {@link Inspect} on given fields. + * + * @return a string representation of given object + */ + CharSequence stringify(); + + /** + * Creates a stringify from a given object + * + * @param object an object to inspect + * @return a stringify + */ + static Stringify of(Object object) { + return new DefaultStringify(object); + } + + @Override + Stringify mode(Mode mode); + + @Override + Stringify beanFactory(BeanFactory beanFactory); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/AlwaysTruePredicate.java b/src/main/java/pl/wavesoftware/utils/stringify/api/AlwaysTruePredicate.java new file mode 100644 index 0000000..c6c50bd --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/AlwaysTruePredicate.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.api; + +import java.util.function.Predicate; + +/** + * A + * @author Krzysztof Suszynski + * @since 27.04.18 + */ +public final class AlwaysTruePredicate implements Predicate { + @Override + public boolean test(InspectionPoint inspectionPoint) { + return true; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java b/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java new file mode 100644 index 0000000..87c6ad3 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.api; + +import pl.wavesoftware.utils.stringify.spi.BeanFactory; +import pl.wavesoftware.utils.stringify.spi.Configurator; + +/** + * A interface that represents a configuration options for this library + *

+ * To use that one should implement {@link Configurator} with Java's + * {@link java.util.ServiceLoader ServiceLoader} mechanism. + *

+ * To do that, create on your classpath, a file: + *

META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
+ * + *

+ * In that file, place a fully qualified class name of your class that implements + * {@link Configurator} interface. It should be called first time you + * use an {@link pl.wavesoftware.utils.stringify.Stringify Stringify} to inspect + * an object. + * + * @see Configurator + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +public interface Configuration { + /** + * Configures a mode in which resolver operates + * + * @param mode a mode to set + * @return a self reference + */ + Configuration mode(Mode mode); + + /** + * Configures a predicate factory to be used to load implementation of predicates used + * + * @param beanFactory a predicate factory + * @return a self reference + */ + Configuration beanFactory(BeanFactory beanFactory); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/DisplayNull.java b/src/main/java/pl/wavesoftware/utils/stringify/api/DisplayNull.java similarity index 50% rename from src/main/java/pl/wavesoftware/utils/stringify/configuration/DisplayNull.java rename to src/main/java/pl/wavesoftware/utils/stringify/api/DisplayNull.java index 1816139..e33675a 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/DisplayNull.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/DisplayNull.java @@ -1,4 +1,20 @@ -package pl.wavesoftware.utils.stringify.configuration; +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.api; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/DoNotInspect.java b/src/main/java/pl/wavesoftware/utils/stringify/api/DoNotInspect.java similarity index 54% rename from src/main/java/pl/wavesoftware/utils/stringify/configuration/DoNotInspect.java rename to src/main/java/pl/wavesoftware/utils/stringify/api/DoNotInspect.java index 15d35b4..edb1e4e 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/DoNotInspect.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/DoNotInspect.java @@ -1,18 +1,33 @@ -package pl.wavesoftware.utils.stringify.configuration; +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ -import pl.wavesoftware.utils.stringify.lang.Predicate; +package pl.wavesoftware.utils.stringify.api; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.function.Predicate; /** * When running in {@link Mode#PROMISCUOUS} this annotation can be used to exclude a * field from inspection. * * @author Krzysztof Suszynski - * @since 27.04.18 + * @since 1.0.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/Inspect.java b/src/main/java/pl/wavesoftware/utils/stringify/api/Inspect.java old mode 100644 new mode 100755 similarity index 54% rename from src/main/java/pl/wavesoftware/utils/stringify/configuration/Inspect.java rename to src/main/java/pl/wavesoftware/utils/stringify/api/Inspect.java index cbd379f..5283412 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/Inspect.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/Inspect.java @@ -1,11 +1,26 @@ -package pl.wavesoftware.utils.stringify.configuration; +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ -import pl.wavesoftware.utils.stringify.lang.Predicate; +package pl.wavesoftware.utils.stringify.api; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.function.Predicate; /** * If {@link Mode} is set to {@link Mode#QUIET} (by default), this annotation @@ -13,7 +28,7 @@ *

* If {@link Mode} is set to {@link Mode#PROMISCUOUS} this annotation has no function. * - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/InspectionPoint.java b/src/main/java/pl/wavesoftware/utils/stringify/api/InspectionPoint.java new file mode 100644 index 0000000..611c03f --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/InspectionPoint.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.api; + +import java.lang.reflect.Field; +import java.util.function.Supplier; + +/** + * This interface represents a inspection point in some object. + * + * @author Krzysztof Suszynski + * @since 1.0.0 + */ +public interface InspectionPoint { + /** + * Get field representation of inspection point + * @return a field + */ + Field getField(); + + /** + * Get object that contains this inspection point + * @return an object + */ + Object getContainingObject(); + + /** + * Get a field value supplier + * + * @return a supplier of a field value + */ + Supplier getValueSupplier(); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/Mode.java b/src/main/java/pl/wavesoftware/utils/stringify/api/Mode.java new file mode 100644 index 0000000..c04050b --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/Mode.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.api; + +/** + * A mode of operation. In {@link #PROMISCUOUS} mode every defined field is + * automatically inspected unless the field is annotated with {@link DoNotInspect} annotation. + *

+ * In {@link #QUIET} mode only fields annotated with {@link Inspect} will get inspected. + * + * @author Krzysztof Suszynski + * @since 1.0.0 + */ +public enum Mode { + PROMISCUOUS, QUIET; + + public static final Mode DEFAULT_MODE = PROMISCUOUS; +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/api/package-info.java new file mode 100644 index 0000000..002ac08 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ + +/** + * @author Krzysztof Suszynski + * @since 20.04.18 + */ +@ReturnTypesAreNonnullByDefault +@ParametersAreNonnullByDefault +package pl.wavesoftware.utils.stringify.api; + +import pl.wavesoftware.eid.api.ReturnTypesAreNonnullByDefault; +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/AlwaysTruePredicate.java b/src/main/java/pl/wavesoftware/utils/stringify/configuration/AlwaysTruePredicate.java deleted file mode 100644 index 71e6a67..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/AlwaysTruePredicate.java +++ /dev/null @@ -1,14 +0,0 @@ -package pl.wavesoftware.utils.stringify.configuration; - -import pl.wavesoftware.utils.stringify.lang.Predicate; - -/** - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public final class AlwaysTruePredicate implements Predicate { - @Override - public boolean test(InspectionPoint inspectionPoint) { - return true; - } -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/BeanFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/configuration/BeanFactory.java deleted file mode 100644 index 413b1c7..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/BeanFactory.java +++ /dev/null @@ -1,9 +0,0 @@ -package pl.wavesoftware.utils.stringify.configuration; - -/** - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public interface BeanFactory { - T create(Class contractClass); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/InspectionPoint.java b/src/main/java/pl/wavesoftware/utils/stringify/configuration/InspectionPoint.java deleted file mode 100644 index e2e03e8..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/InspectionPoint.java +++ /dev/null @@ -1,32 +0,0 @@ -package pl.wavesoftware.utils.stringify.configuration; - -import pl.wavesoftware.utils.stringify.lang.Supplier; - -import java.lang.reflect.Field; - -/** - * This interface represents a inspection point in some object. - * - * @author Krzysztof Suszynski - * @since 30.04.18 - */ -public interface InspectionPoint { - /** - * Get field representation of inspection point - * @return a field - */ - Field getField(); - - /** - * Get object that contains this inspection point - * @return an object - */ - Object getContainingObject(); - - /** - * Get a field value supplier - * - * @return a supplier of a field value - */ - Supplier getValueSupplier(); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/Mode.java b/src/main/java/pl/wavesoftware/utils/stringify/configuration/Mode.java deleted file mode 100644 index 33eb49d..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/Mode.java +++ /dev/null @@ -1,16 +0,0 @@ -package pl.wavesoftware.utils.stringify.configuration; - -/** - * A mode of operation. In {@link #PROMISCUOUS} mode every defined field is - * automatically inspected unless the field is annotated with {@link DoNotInspect} annotation. - *

- * In {@link #QUIET} mode only fields annotated with {@link Inspect} will get inspected. - * - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public enum Mode { - PROMISCUOUS, QUIET; - - public static final Mode DEFAULT_MODE = PROMISCUOUS; -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/configuration/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/configuration/package-info.java deleted file mode 100644 index 24dc5c2..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/configuration/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @author Krzysztof Suszynski - * @since 20.04.18 - */ -@ParametersAreNonnullByDefault -package pl.wavesoftware.utils.stringify.configuration; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/BeanFactoryCache.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/BeanFactoryCache.java new file mode 100644 index 0000000..657b1fd --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/BeanFactoryCache.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import lombok.RequiredArgsConstructor; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +@RequiredArgsConstructor +final class BeanFactoryCache implements BeanFactory { + private final Map, Object> created = new ConcurrentHashMap<>(); + private final Supplier delegate; + + @Override + public T create(final Class contractClass) { + if (isCached(contractClass)) { + return getFromCache(contractClass); + } + T predicate = delegate.get().create(contractClass); + put(contractClass, predicate); + return predicate; + } + + void clear() { + created.clear(); + } + + @SuppressWarnings("unchecked") + private T getFromCache(final Class contractClass) { + Object bean = created.get(contractClass); + return (T) bean; + } + + private void put(Class contractClass, T bean) { + created.put(contractClass, bean); + } + + private boolean isCached(Class contractClass) { + return created.containsKey(contractClass); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/BootAwareBootFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/BootAwareBootFactory.java new file mode 100755 index 0000000..9c7aa65 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/BootAwareBootFactory.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; +import pl.wavesoftware.utils.stringify.spi.BootingAware; + +import static pl.wavesoftware.utils.stringify.impl.InspectionUtils.safeInspect; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +final class BootAwareBootFactory implements BeanFactory, Inspectable { + private static final Logger LOGGER = + LoggerFactory.getLogger(BootAwareBootFactory.class); + private final BeanFactory delegate; + private final Object target; + + BootAwareBootFactory(BeanFactory delegate, Object target) { + this.delegate = delegate; + this.target = target; + } + + @Override + public T create(Class contractClass) { + return getBeanFactory(contractClass).create(contractClass); + } + + private BeanFactory getBeanFactory(Class contractClass) { + if (delegate instanceof BootingAware) { + BootingAware bootingAware = (BootingAware) delegate; + if (!bootingAware.isReady() && LOGGER.isWarnEnabled()) { + LOGGER.error( + "Given BeanFactory {} is reporting that it's not ready, but Stringify" + + " has been already invoked for {} while trying to resolve {}. This is " + + "usually some race condition issues. Using default BeanFactory as a " + + "fallback for this call.", + safeInspect(delegate), safeInspect(target), contractClass + ); + return DefaultConfiguration.DEFAULT_BEAN_FACTORY; + } + } + return delegate; + } + + @Override + public String inspect() { + return safeInspect(delegate); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/CharSequenceInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/CharSequenceInspector.java index 22c1492..9633b14 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/CharSequenceInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/CharSequenceInspector.java @@ -1,12 +1,30 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; +import java.util.function.Function; + /** * @author Krzysztof Suszynski * @since 20.04.18 */ final class CharSequenceInspector implements ObjectInspector { @Override - public boolean consentTo(Object candidate, State state) { + public boolean consentTo(Object candidate, InspectionContext inspectionContext) { return candidate instanceof CharSequence; } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/CharacterInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/CharacterInspector.java index b6fea26..7c60228 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/CharacterInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/CharacterInspector.java @@ -1,5 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; +import java.util.function.Function; + /** * @author Krzysztof Suszynski * @since 20.04.18 @@ -7,7 +25,7 @@ final class CharacterInspector implements ObjectInspector { @Override - public boolean consentTo(Object candidate, State state) { + public boolean consentTo(Object candidate, InspectionContext inspectionContext) { return candidate instanceof Character; } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ClassLocator.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ClassLocator.java index c6cc4f5..fc5c669 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ClassLocator.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/ClassLocator.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.AccessLevel; @@ -8,7 +24,7 @@ import static pl.wavesoftware.eid.utils.EidPreconditions.checkNotNull; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ @RequiredArgsConstructor(access = AccessLevel.PACKAGE) diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultBeanFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultBeanFactory.java new file mode 100755 index 0000000..4669def --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultBeanFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +final class DefaultBeanFactory implements BeanFactory { + private final ReflectionBeanFactory reflectionBeanFactory = new ReflectionBeanFactory(); + + @Override + public T create(Class contractClass) { + return reflectionBeanFactory.create(contractClass); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfiguration.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfiguration.java new file mode 100644 index 0000000..6bf7fd7 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import pl.wavesoftware.utils.stringify.api.Configuration; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +final class DefaultConfiguration implements Configuration { + static final DefaultBeanFactory DEFAULT_BEAN_FACTORY = + new DefaultBeanFactory(); + + private Mode mode = Mode.DEFAULT_MODE; + private BeanFactory beanFactory = DEFAULT_BEAN_FACTORY; + + @Override + public Configuration mode(Mode mode) { + this.mode = mode; + return this; + } + + @Override + public Configuration beanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + return this; + } + + DefaultConfiguration dup() { + DefaultConfiguration dup = new DefaultConfiguration(); + dup.beanFactory = beanFactory; + dup.mode = mode; + return dup; + } + + Mode getMode() { + return mode; + } + + BeanFactory getBeanFactory() { + return beanFactory; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfigurationLoader.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfigurationLoader.java new file mode 100644 index 0000000..5a5bebf --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultConfigurationLoader.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import pl.wavesoftware.utils.stringify.spi.Configurator; + +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +final class DefaultConfigurationLoader { + private DefaultConfigurationLoader() { + // not reachable + } + + static DefaultConfiguration load() { + ServiceLoader serviceLoader = ServiceLoader.load(Configurator.class); + DefaultConfiguration configuration = new DefaultConfiguration(); + StreamSupport.stream(serviceLoader.spliterator(), false) + .forEach(configurator -> configurator.configure(configuration)); + return configuration; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultInspectionContext.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultInspectionContext.java new file mode 100644 index 0000000..1514e2e --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultInspectionContext.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * @author Krzysztof Suszynski + * @since 1.0.0 + */ +final class DefaultInspectionContext implements InspectionContext { + private static final Object CONTAIN = new Object(); + + private final Map resolved; + + DefaultInspectionContext() { + this(new IdentityHashMap<>()); + } + + private DefaultInspectionContext(Map resolved) { + this.resolved = resolved; + } + + @Override + public boolean wasInspected(Object object) { + return resolved.containsKey(object); + } + + @Override + public void markIsInspected(Object object) { + resolved.put(object, CONTAIN); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultStringify.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultStringify.java new file mode 100644 index 0000000..5e46d04 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/DefaultStringify.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import pl.wavesoftware.utils.stringify.Stringify; +import pl.wavesoftware.utils.stringify.api.Inspect; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +/** + * A default implementation of {@link Stringify}. + * + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +public final class DefaultStringify implements Stringify { + + private static final DefaultConfiguration CONFIGURATION = + DefaultConfigurationLoader.load(); + + private final ToStringResolverImpl resolver; + + /** + * A default constructor for Stringify. + * + * @param target a target object to inspect + */ + public DefaultStringify(Object target) { + resolver = new ToStringResolverImpl(target, CONFIGURATION.dup()); + } + + /** + * Creates string representation of given object using {@link Inspect} on given fields. + * + * @return a string representation of given object + */ + @Override + public CharSequence stringify() { + return resolver.resolve(); + } + + @Override + public String toString() { + return stringify().toString(); + } + + @Override + public int length() { + return stringify().length(); + } + + @Override + public char charAt(int index) { + return stringify().charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return stringify().subSequence(start, end); + } + + @Override + public Stringify mode(Mode mode) { + resolver.mode(mode); + return this; + } + + @Override + public Stringify beanFactory(BeanFactory beanFactory) { + resolver.beanFactory(beanFactory); + return this; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/FallbackBootFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/FallbackBootFactory.java new file mode 100755 index 0000000..323aedc --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/FallbackBootFactory.java @@ -0,0 +1,39 @@ +package pl.wavesoftware.utils.stringify.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +import javax.annotation.Nullable; + +import static pl.wavesoftware.eid.utils.EidPreconditions.checkState; +import static pl.wavesoftware.utils.stringify.impl.InspectionUtils.safeInspect; + +final class FallbackBootFactory implements BeanFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(FallbackBootFactory.class); + private static final BeanFactory DEFAULT = new DefaultBeanFactory(); + private final BeanFactory beanFactory; + + FallbackBootFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @Override + public T create(Class contractClass) { + try { + @Nullable T bean = beanFactory.create(contractClass); + checkState(bean != null, "20190705:114553"); + return bean; + } catch (RuntimeException ex) { + LOGGER.error( + MessageFormatter.format( + "Configured BeanFactory {} thrown an exception while trying to " + + "resolve {}. Fallback to default BeanFactory.", + safeInspect(beanFactory), contractClass + ).getMessage(), ex + ); + return DEFAULT.create(contractClass); + } + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/Function.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/Function.java deleted file mode 100644 index d2622b8..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/Function.java +++ /dev/null @@ -1,9 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszynski - * @since 20.04.18 - */ -interface Function { - O apply(I input); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/HibernateLazyChecker.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/HibernateLazyChecker.java index 489d201..cb7523a 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/HibernateLazyChecker.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/HibernateLazyChecker.java @@ -1,17 +1,34 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; -import pl.wavesoftware.eid.utils.EidPreconditions; +import pl.wavesoftware.eid.utils.UnsafeSupplier; import javax.annotation.Nonnull; import java.lang.reflect.Method; -import static pl.wavesoftware.eid.utils.EidPreconditions.tryToExecute; +import static pl.wavesoftware.eid.utils.EidExecutions.tryToExecute; + /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ -final class HibernateLazyChecker implements JPALazyChecker { +final class HibernateLazyChecker implements JpaLazyChecker { private static final ClassLocator HIBERNATE_LOCATOR = new ClassLocator("org.hibernate.Hibernate"); private static Method isInitializedMethod; @@ -25,11 +42,11 @@ public boolean isLazy(final Object candidate) { Class cls = HIBERNATE_LOCATOR.get(); final Method method = getIsInitializedMethod(cls); return !tryToExecute( - new EidPreconditions.UnsafeSupplier() { + new UnsafeSupplier() { @Override @Nonnull public Boolean get() throws Exception { - return Boolean.class.cast(method.invoke(null, candidate)); + return (Boolean) method.invoke(null, candidate); } }, "20180418:231314" @@ -39,7 +56,7 @@ public Boolean get() throws Exception { private static Method getIsInitializedMethod(final Class hibernateClass) { if (isInitializedMethod == null) { isInitializedMethod = tryToExecute( - new EidPreconditions.UnsafeSupplier() { + new UnsafeSupplier() { @Override @Nonnull public Method get() throws Exception { diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectFieldPredicate.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectFieldPredicate.java index fab58e9..a9f3ea1 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectFieldPredicate.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectFieldPredicate.java @@ -1,6 +1,22 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; /** * @author Krzysztof Suszynski diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspectable.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspectable.java new file mode 100755 index 0000000..349c918 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspectable.java @@ -0,0 +1,5 @@ +package pl.wavesoftware.utils.stringify.impl; + +interface Inspectable { + String inspect(); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingField.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingField.java index 967b2f6..54057f2 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingField.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingField.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; /** diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldFactory.java index e9e8123..4c8b54b 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldFactory.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldFactory.java @@ -1,9 +1,27 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.configuration.Mode; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; +import pl.wavesoftware.utils.stringify.api.Mode; + +import java.util.function.Supplier; /** * @author Krzysztof Suszynski @@ -11,7 +29,7 @@ */ @RequiredArgsConstructor final class InspectingFieldFactory { - private final Mode mode; + private final Supplier mode; InspectingField create(InspectionPoint inspectionPoint, BeanFactory beanFactory) { @@ -19,7 +37,7 @@ InspectingField create(InspectionPoint inspectionPoint, } private InspectFieldPredicate createPredicate(BeanFactory beanFactory) { - if (mode == Mode.PROMISCUOUS) { + if (mode.get() == Mode.PROMISCUOUS) { return new PromiscuousInspectFieldPredicate(beanFactory); } else { return new QuietInspectFieldPredicate(beanFactory); diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldImpl.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldImpl.java index 2fe1b29..f588cea 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldImpl.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectingFieldImpl.java @@ -1,14 +1,30 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.DisplayNull; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; +import pl.wavesoftware.utils.stringify.api.DisplayNull; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-30 */ @RequiredArgsConstructor diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionContext.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionContext.java new file mode 100644 index 0000000..69cf99e --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionContext.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +/** + * @author Krzysztof Suszynski + * @since 20.04.18 + */ +interface InspectionContext { + boolean wasInspected(Object object); + void markIsInspected(Object object); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImpl.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImpl.java index 0f6ca64..a4f2a2a 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImpl.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImpl.java @@ -1,15 +1,31 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.Getter; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.eid.utils.EidPreconditions; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.lang.Supplier; +import pl.wavesoftware.eid.utils.UnsafeSupplier; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; import javax.annotation.Nonnull; import java.lang.reflect.Field; +import java.util.function.Supplier; -import static pl.wavesoftware.eid.utils.EidPreconditions.tryToExecute; +import static pl.wavesoftware.eid.utils.EidExecutions.tryToExecute; /** * @author Krzysztof Suszynski @@ -23,20 +39,17 @@ final class InspectionPointImpl implements InspectionPoint { @Override public Supplier getValueSupplier() { - return new Supplier() { - @Override - public Object get() { - try (final FieldAccessiblier accessiblier = new FieldAccessiblier(getField())) { - return tryToExecute(new EidPreconditions.UnsafeSupplier() { - @Override - @Nonnull - public Object get() throws IllegalAccessException { - return accessiblier - .getField() - .get(getContainingObject()); - } - }, "20180430:113514"); - } + return () -> { + try (final FieldAccessiblier accessiblier = new FieldAccessiblier(getField())) { + return tryToExecute(new UnsafeSupplier() { + @Override + @Nonnull + public Object get() throws IllegalAccessException { + return accessiblier + .getField() + .get(getContainingObject()); + } + }, "20180430:113514"); } }; } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionUtils.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionUtils.java new file mode 100755 index 0000000..64d0343 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/InspectionUtils.java @@ -0,0 +1,14 @@ +package pl.wavesoftware.utils.stringify.impl; + +final class InspectionUtils { + private InspectionUtils() { + // nothing + } + + static String safeInspect(Object object) { + if (object instanceof Inspectable) { + return ((Inspectable) object).inspect(); + } + return object.getClass().getName() + '@' + Integer.toHexString(object.hashCode()); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspector.java new file mode 100644 index 0000000..9bd6076 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/Inspector.java @@ -0,0 +1,169 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import pl.wavesoftware.utils.stringify.api.InspectionPoint; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Function; + +import static pl.wavesoftware.eid.utils.EidExecutions.tryToExecute; + +/** + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +final class Inspector implements ToStringResolver { + private static final Iterable OBJECT_INSPECTORS = Arrays.asList( + new CharSequenceInspector(), + new PrimitiveInspector(), + new CharacterInspector(), + new JpaLazyInspector(), + new MapInspector(), + new IterableInspector(), + new RecursionInspector() + ); + + private final DefaultConfiguration configuration; + private final Object target; + private final InspectionContext inspectionContext; + private final Function alternative; + private final BeanFactoryCache beanFactoryCache; + private final InspectingFieldFactory inspectingFieldFactory; + + Inspector( + DefaultConfiguration configuration, + Object target, + InspectionContext inspectionContext, + Function alternative, + BeanFactoryCache beanFactoryCache, + InspectingFieldFactory inspectingFieldFactory + ) { + this.configuration = configuration; + this.target = target; + this.inspectionContext = inspectionContext; + this.alternative = alternative; + this.beanFactoryCache = beanFactoryCache; + this.inspectingFieldFactory = inspectingFieldFactory; + } + + @Override + public CharSequence resolve() { + inspectionContext.markIsInspected(target); + StringBuilder sb = new StringBuilder(); + sb.append('<'); + sb.append(target.getClass().getSimpleName()); + CharSequence props = propertiesForToString(); + if (props.length() != 0) { + sb.append(' '); + sb.append(props); + } + sb.append('>'); + return sb; + } + + private CharSequence propertiesForToString() { + Map props; + props = inspectTargetAsClass(target.getClass()); + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : props.entrySet()) { + String fieldName = entry.getKey(); + CharSequence fieldStringValue = entry.getValue(); + sb.append(fieldName); + sb.append("="); + sb.append(fieldStringValue); + sb.append(", "); + } + if (sb.length() > 0) { + sb.deleteCharAt(sb.length() - 1); + sb.deleteCharAt(sb.length() - 1); + } + return sb; + } + + private Map inspectTargetAsClass(Class type) { + Class supertype = type.getSuperclass(); + Map props; + if (supertype == null || supertype.equals(Object.class)) { + props = new LinkedHashMap<>(); + } else { + props = inspectTargetAsClass(supertype); + } + inspectFields(type.getDeclaredFields(), props); + return props; + } + + private void inspectFields(Field[] fields, + Map properties) { + for (Field field : fields) { + InspectionPoint inspectionPoint = createInspectionPoint(field); + InspectingField inspectingField = inspectingFieldFactory.create(inspectionPoint, beanFactoryCache); + if (inspectingField.shouldInspect()) { + inspectAnnotatedField(properties, field, inspectingField); + } + } + } + + private InspectionPoint createInspectionPoint(Field field) { + return new InspectionPointImpl(field, target); + } + + private void inspectAnnotatedField(final Map properties, + final Field field, + final InspectingField inspectingField) { + tryToExecute(() -> { + ensureAccessible(field); + Object value = field.get(target); + if (value == null) { + if (inspectingField.showNull()) { + properties.put(field.getName(), null); + } + } else { + properties.put(field.getName(), inspectObject(value)); + } + }, "20130422:154938"); + } + + private static void ensureAccessible(Field field) { + if (!field.isAccessible()) { + field.setAccessible(true); + } + } + + CharSequence inspectObject(Object object) { + for (ObjectInspector inspector : OBJECT_INSPECTORS) { + if (inspector.consentTo(object, inspectionContext)) { + return inspector.inspect(object, alternative); + } + } + ToStringResolverImpl sub = new ToStringResolverImpl( + object, + configuration, + inspectionContext, + beanFactoryCache, + inspectingFieldFactory + ); + return sub.resolve(); + } + + void clear() { + beanFactoryCache.clear(); + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/IterableInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/IterableInspector.java index e4b51e6..05a36eb 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/IterableInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/IterableInspector.java @@ -1,12 +1,30 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; +import java.util.function.Function; + /** * @author Krzysztof Suszynski * @since 20.04.18 */ final class IterableInspector implements ObjectInspector { @Override - public boolean consentTo(Object candidate, State state) { + public boolean consentTo(Object candidate, InspectionContext inspectionContext) { return candidate instanceof Iterable; } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyChecker.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyChecker.java deleted file mode 100644 index cd8df22..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyChecker.java +++ /dev/null @@ -1,15 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszyński - * @since 2018-04-18 - */ -interface JPALazyChecker { - /** - * Checks if given object is lazy - * - * @param candidate a candidate to be checked - * @return true, if object is lazy - */ - boolean isLazy(Object candidate); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyCheckerFacade.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyCheckerFacade.java deleted file mode 100644 index c2ccfcd..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyCheckerFacade.java +++ /dev/null @@ -1,40 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -/** - * @author Krzysztof Suszyński - * @since 2018-04-18 - */ -@NoArgsConstructor(access = AccessLevel.PACKAGE) -final class JPALazyCheckerFacade implements JPALazyChecker { - private static final JPALazyChecker NOOP_CHECKER = new JPALazyChecker() { - @Override - public boolean isLazy(Object candidate) { - return false; - } - }; - - private JPALazyChecker lazyChecker; - - @Override - public boolean isLazy(Object candidate) { - JPALazyChecker checker = getImpl(); - return checker.isLazy(candidate); - } - - private JPALazyChecker getImpl() { - if (lazyChecker == null) { - lazyChecker = resolveImpl(); - } - return lazyChecker; - } - - private static JPALazyChecker resolveImpl() { - if (HibernateLazyChecker.isSuitable()) { - return new HibernateLazyChecker(); - } - return NOOP_CHECKER; - } -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyInspector.java deleted file mode 100644 index 3699357..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/JPALazyInspector.java +++ /dev/null @@ -1,20 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszynski - * @since 20.04.18 - */ -final class JPALazyInspector implements ObjectInspector { - private static final JPALazyChecker LAZY_CHECKER = new JPALazyCheckerFacade(); - - @Override - public boolean consentTo(Object candidate, State state) { - return LAZY_CHECKER.isLazy(candidate); - } - - @Override - public CharSequence inspect(Object object, - Function alternative) { - return "⁂Lazy"; - } -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyChecker.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyChecker.java new file mode 100644 index 0000000..2304730 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyChecker.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +/** + * @author Krzysztof Suszynski + * @since 2018-04-18 + */ +interface JpaLazyChecker { + /** + * Checks if given object is lazy + * + * @param candidate a candidate to be checked + * @return true, if object is lazy + */ + boolean isLazy(Object candidate); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyCheckerFacade.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyCheckerFacade.java new file mode 100644 index 0000000..e918583 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyCheckerFacade.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * @author Krzysztof Suszynski + * @since 2018-04-18 + */ +@NoArgsConstructor(access = AccessLevel.PACKAGE) +final class JpaLazyCheckerFacade implements JpaLazyChecker { + private static final JpaLazyChecker NOOP_CHECKER = candidate -> false; + + private JpaLazyChecker lazyChecker; + + @Override + public boolean isLazy(Object candidate) { + JpaLazyChecker checker = getImpl(); + return checker.isLazy(candidate); + } + + private JpaLazyChecker getImpl() { + if (lazyChecker == null) { + lazyChecker = resolveImpl(); + } + return lazyChecker; + } + + private static JpaLazyChecker resolveImpl() { + if (HibernateLazyChecker.isSuitable()) { + return new HibernateLazyChecker(); + } + return NOOP_CHECKER; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyInspector.java new file mode 100644 index 0000000..60324b1 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/JpaLazyInspector.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; + +import java.util.function.Function; + +/** + * @author Krzysztof Suszynski + * @since 20.04.18 + */ +final class JpaLazyInspector implements ObjectInspector { + private static final JpaLazyChecker LAZY_CHECKER = new JpaLazyCheckerFacade(); + + @Override + public boolean consentTo(Object candidate, InspectionContext inspectionContext) { + return LAZY_CHECKER.isLazy(candidate); + } + + @Override + public CharSequence inspect(Object object, + Function alternative) { + return "⁂Lazy"; + } +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/MapInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/MapInspector.java index ccd0974..4e12542 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/MapInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/MapInspector.java @@ -1,6 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import java.util.Map; +import java.util.function.Function; /** * @author Krzysztof Suszynski @@ -10,7 +27,7 @@ final class MapInspector implements ObjectInspector { @Override public boolean consentTo(Object candidate, - State state) { + InspectionContext inspectionContext) { return candidate instanceof Map; } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ObjectInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ObjectInspector.java index 1acfb65..08baef8 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ObjectInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/ObjectInspector.java @@ -1,12 +1,31 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; +import java.util.function.Function; + /** * @author Krzysztof Suszynski * @since 20.04.18 */ interface ObjectInspector { - boolean consentTo(Object candidate, - State state); - CharSequence inspect(Object object, - Function alternative); + boolean consentTo(Object candidate, InspectionContext inspectionContext); + + CharSequence inspect( + Object object, Function alternative + ); } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/PrimitiveInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/PrimitiveInspector.java index fa484c3..fca9f82 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/PrimitiveInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/PrimitiveInspector.java @@ -1,6 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import java.util.Date; +import java.util.function.Function; /** * @author Krzysztof Suszynski @@ -13,7 +30,7 @@ final class PrimitiveInspector implements ObjectInspector { @Override public boolean consentTo(Object candidate, - State state) { + InspectionContext inspectionContext) { return isPrimitive(candidate); } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/PromiscuousInspectFieldPredicate.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/PromiscuousInspectFieldPredicate.java index ca3fc00..2510382 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/PromiscuousInspectFieldPredicate.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/PromiscuousInspectFieldPredicate.java @@ -1,13 +1,30 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.AlwaysTruePredicate; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; -import pl.wavesoftware.utils.stringify.configuration.DoNotInspect; -import pl.wavesoftware.utils.stringify.configuration.Inspect; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.lang.Predicate; +import pl.wavesoftware.utils.stringify.api.AlwaysTruePredicate; +import pl.wavesoftware.utils.stringify.api.DoNotInspect; +import pl.wavesoftware.utils.stringify.api.Inspect; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +import java.util.function.Predicate; /** * @author Krzysztof Suszynski diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/QuietInspectFieldPredicate.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/QuietInspectFieldPredicate.java index a583ef1..bf9681e 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/QuietInspectFieldPredicate.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/QuietInspectFieldPredicate.java @@ -1,12 +1,29 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.AlwaysTruePredicate; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; -import pl.wavesoftware.utils.stringify.configuration.Inspect; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.lang.Predicate; +import pl.wavesoftware.utils.stringify.api.AlwaysTruePredicate; +import pl.wavesoftware.utils.stringify.api.Inspect; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; + +import java.util.function.Predicate; /** * @author Krzysztof Suszynski diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/RecursionInspector.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/RecursionInspector.java index d804bd7..98d45a6 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/RecursionInspector.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/RecursionInspector.java @@ -1,13 +1,31 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; +import java.util.function.Function; + /** * @author Krzysztof Suszynski * @since 20.04.18 */ final class RecursionInspector implements ObjectInspector { @Override - public boolean consentTo(Object candidate, State state) { - return state.wasInspected(candidate); + public boolean consentTo(Object candidate, InspectionContext context) { + return context.wasInspected(candidate); } @Override diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ReflectionBeanFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ReflectionBeanFactory.java old mode 100644 new mode 100755 index 7fbbe2f..db677e0 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ReflectionBeanFactory.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/ReflectionBeanFactory.java @@ -1,52 +1,46 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; -import pl.wavesoftware.eid.utils.EidPreconditions; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; +import pl.wavesoftware.eid.utils.UnsafeSupplier; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; -import static pl.wavesoftware.eid.utils.EidPreconditions.tryToExecute; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import static pl.wavesoftware.eid.utils.EidExecutions.tryToExecute; /** * @author Krzysztof Suszynski * @since 27.04.18 */ final class ReflectionBeanFactory implements BeanFactory { - private final Map, Object> created = - new HashMap<>(); - @Override - public T create(final Class contractClass) { - if (isCached(contractClass)) { - return getFromCache(contractClass); - } - T predicate = instantinate(contractClass); - put(contractClass, predicate); - return predicate; - } - - @SuppressWarnings("unchecked") - private T getFromCache(final Class contractClass) { - Object bean = created.get(contractClass); - return (T) bean; - } - - private void put(Class contractClass, T bean) { - created.put(contractClass, bean); - } - - private boolean isCached(Class contractClass) { - return created.containsKey(contractClass); - } - - private T instantinate(final Class contractClass) { - return tryToExecute(new EidPreconditions.UnsafeSupplier() { + public T create(Class contractClass) { + return tryToExecute(new UnsafeSupplier() { @Override @Nonnull - public T get() throws IllegalAccessException, InstantiationException { - return contractClass.newInstance(); + public T get() throws IllegalAccessException, InstantiationException, + InvocationTargetException, NoSuchMethodException { + Constructor constructor = contractClass.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); } }, "20180427:171402"); } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/State.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/State.java deleted file mode 100644 index d719c7b..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/State.java +++ /dev/null @@ -1,10 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszynski - * @since 20.04.18 - */ -public interface State { - boolean wasInspected(Object object); - void markIsInspected(Object object); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolver.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolver.java index 12a1e19..2582cd8 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolver.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolver.java @@ -1,29 +1,28 @@ -package pl.wavesoftware.utils.stringify.impl; +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ -import pl.wavesoftware.utils.stringify.configuration.Mode; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; +package pl.wavesoftware.utils.stringify.impl; /** + * Resolves an representation of object to a char sequence. + * * @author Krzysztof Suszynski - * @since 27.04.18 + * @since 1.0.0 */ -public interface ToStringResolver { - /** - * Configures a mode in which resolver operates - * - * @param mode a mode to set - * @return a self reference - */ - ToStringResolver withMode(Mode mode); - - /** - * Configures a predicate factory to be used to load implementation of predicates used - * - * @param beanFactory a predicate factory - * @return a self reference - */ - ToStringResolver withBeanFactory(BeanFactory beanFactory); - +interface ToStringResolver { /** * Resolves a {@link String} representation of given object. * diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactory.java deleted file mode 100644 index 9582aef..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactory.java +++ /dev/null @@ -1,9 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public interface ToStringResolverFactory { - ToStringResolver create(Object target); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactoryImpl.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactoryImpl.java deleted file mode 100644 index 6a588a8..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverFactoryImpl.java +++ /dev/null @@ -1,12 +0,0 @@ -package pl.wavesoftware.utils.stringify.impl; - -/** - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public final class ToStringResolverFactoryImpl implements ToStringResolverFactory { - @Override - public ToStringResolver create(Object target) { - return new ToStringResolverImpl(target); - } -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverImpl.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverImpl.java old mode 100644 new mode 100755 index 8732cba..04ba80b --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverImpl.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/ToStringResolverImpl.java @@ -1,207 +1,94 @@ -package pl.wavesoftware.utils.stringify.impl; +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ -import pl.wavesoftware.eid.utils.EidPreconditions; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.configuration.Mode; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; +package pl.wavesoftware.utils.stringify.impl; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.IdentityHashMap; -import java.util.LinkedHashMap; -import java.util.Map; +import pl.wavesoftware.utils.stringify.api.Configuration; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; -import static pl.wavesoftware.eid.utils.EidPreconditions.tryToExecute; +import java.util.function.Function; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ -final class ToStringResolverImpl implements ToStringResolver { - private static final Iterable OBJECT_INSPECTORS = Arrays.asList( - new CharSequenceInspector(), - new PrimitiveInspector(), - new CharacterInspector(), - new JPALazyInspector(), - new MapInspector(), - new IterableInspector(), - new RecursionInspector() - ); - - private final Object target; - private InspectingFieldFactory inspectingFieldFactory; - private BeanFactory beanFactory; - private final State state; - private final Function alternative; +final class ToStringResolverImpl implements ToStringResolver, Configuration { + private final DefaultConfiguration configuration; + private final Inspector inspector; /** * A default constructor * - * @param target a target object to resolve + * @param target a target object to resolve + * @param configuration a configuration */ - ToStringResolverImpl(Object target) { + ToStringResolverImpl(Object target, DefaultConfiguration configuration) { this( target, - new StateImpl(), - new ReflectionBeanFactory(), - new InspectingFieldFactory(Mode.DEFAULT_MODE) + configuration, + new DefaultInspectionContext(), + new BeanFactoryCache(() -> + new FallbackBootFactory( + new BootAwareBootFactory(configuration.getBeanFactory(), target) + ) + ), + new InspectingFieldFactory(configuration::getMode) ); } - private ToStringResolverImpl(Object target, - State state, - BeanFactory beanFactory, - InspectingFieldFactory inspectingFieldFactory) { - this.state = state; - this.target = target; - this.beanFactory = beanFactory; - this.inspectingFieldFactory = inspectingFieldFactory; - this.alternative = new ObjectInspectorImpl(); + ToStringResolverImpl( + Object target, + DefaultConfiguration configuration, + InspectionContext inspectionContext, + BeanFactoryCache beanFactoryCache, + InspectingFieldFactory inspectingFieldFactory + ) { + this.configuration = configuration; + this.inspector = new Inspector( + configuration, target, inspectionContext, new ObjectInspectorImpl(), + beanFactoryCache, inspectingFieldFactory + ); } @Override - public ToStringResolver withMode(Mode mode) { - this.inspectingFieldFactory = new InspectingFieldFactory(mode); - return this; + public CharSequence resolve() { + return inspector.resolve(); } @Override - public ToStringResolver withBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - return this; + public Configuration mode(Mode mode) { + inspector.clear(); + return configuration.mode(mode); } @Override - public CharSequence resolve() { - state.markIsInspected(target); - StringBuilder sb = new StringBuilder(); - sb.append('<'); - sb.append(target.getClass().getSimpleName()); - CharSequence props = propertiesForToString(); - if (props.length() != 0) { - sb.append(' '); - sb.append(props); - } - sb.append('>'); - return sb; - } - - private CharSequence propertiesForToString() { - Map props; - props = inspectTargetAsClass(target.getClass()); - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : props.entrySet()) { - String fieldName = entry.getKey(); - CharSequence fieldStringValue = entry.getValue(); - sb.append(fieldName); - sb.append("="); - sb.append(fieldStringValue); - sb.append(", "); - } - if (sb.length() > 0) { - sb.deleteCharAt(sb.length() - 1); - sb.deleteCharAt(sb.length() - 1); - } - return sb; - } - - private Map inspectTargetAsClass(Class type) { - Class supertype = type.getSuperclass(); - Map props; - if (supertype == null || supertype.equals(Object.class)) { - props = new LinkedHashMap<>(); - } else { - props = inspectTargetAsClass(supertype); - } - inspectFields(type.getDeclaredFields(), props); - return props; - } - - private void inspectFields(Field[] fields, - Map properties) { - for (Field field : fields) { - InspectionPoint inspectionPoint = createInspectionPoint(field); - InspectingField inspectingField = inspectingFieldFactory.create(inspectionPoint, beanFactory); - if (inspectingField.shouldInspect()) { - inspectAnnotatedField(properties, field, inspectingField); - } - } - } - - private InspectionPoint createInspectionPoint(Field field) { - return new InspectionPointImpl(field, target); - } - - private void inspectAnnotatedField(final Map properties, - final Field field, - final InspectingField inspectingField) { - tryToExecute(new EidPreconditions.UnsafeProcedure() { - @Override - public void execute() throws IllegalAccessException { - ensureAccessible(field); - Object value = field.get(target); - if (value == null) { - if (inspectingField.showNull()) { - properties.put(field.getName(), null); - } - } else { - properties.put(field.getName(), inspectObject(value)); - } - } - }, "20130422:154938"); - } - - private void ensureAccessible(Field field) { - if (!field.isAccessible()) { - field.setAccessible(true); - } - } - - private CharSequence inspectObject(Object object) { - for (ObjectInspector inspector : OBJECT_INSPECTORS) { - if (inspector.consentTo(object, state)) { - return inspector.inspect(object, alternative); - } - } - ToStringResolverImpl sub = new ToStringResolverImpl( - object, - state, - beanFactory, - inspectingFieldFactory - ); - return sub.resolve(); + public Configuration beanFactory(BeanFactory beanFactory) { + inspector.clear(); + return configuration.beanFactory(beanFactory); } private final class ObjectInspectorImpl implements Function { @Override public CharSequence apply(Object object) { - return inspectObject(object); + return inspector.inspectObject(object); } - } - - private static final class StateImpl implements State { - private static final Object CONTAIN = new Object(); - - private final Map resolved; - private StateImpl() { - this(new IdentityHashMap<>()); - } - - private StateImpl(Map resolved) { - this.resolved = resolved; - } - - @Override - public boolean wasInspected(Object object) { - return resolved.containsKey(object); - } - - @Override - public void markIsInspected(Object object) { - resolved.put(object, CONTAIN); - } } + } diff --git a/src/main/java/pl/wavesoftware/utils/stringify/impl/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/impl/package-info.java index 01f7ca9..156dc69 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/impl/package-info.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/impl/package-info.java @@ -1,8 +1,26 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ + /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ +@ReturnTypesAreNonnullByDefault @ParametersAreNonnullByDefault package pl.wavesoftware.utils.stringify.impl; +import pl.wavesoftware.eid.api.ReturnTypesAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/lang/Predicate.java b/src/main/java/pl/wavesoftware/utils/stringify/lang/Predicate.java deleted file mode 100644 index 4bc3d6b..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/lang/Predicate.java +++ /dev/null @@ -1,23 +0,0 @@ -package pl.wavesoftware.utils.stringify.lang; - -/** - * Represents a predicate (boolean-valued function) of one argument. - * - *

This is a functional interface - * whose functional method is {@link #test(Object)}. - * - * @param the type of the input to the predicate - * - * @author Krzysztof Suszynski - * @since 27.04.18 - */ -public interface Predicate { - /** - * Evaluates this predicate on the given argument. - * - * @param t the input argument - * @return {@code true} if the input argument matches the predicate, - * otherwise {@code false} - */ - boolean test(T t); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/lang/Supplier.java b/src/main/java/pl/wavesoftware/utils/stringify/lang/Supplier.java deleted file mode 100644 index f57dd32..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/lang/Supplier.java +++ /dev/null @@ -1,24 +0,0 @@ -package pl.wavesoftware.utils.stringify.lang; - -/** - * Represents a supplier of results. - * - *

There is no requirement that a new or distinct result be returned each - * time the supplier is invoked. - * - *

This is a functional interface - * whose functional method is {@link #get()}. - * - * @param the type of results supplied by this supplier - * - * @author Krzysztof Suszynski - * @since 30.04.18 - */ -public interface Supplier { - /** - * Gets a result. - * - * @return a result - */ - T get(); -} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/lang/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/lang/package-info.java deleted file mode 100644 index de57fa7..0000000 --- a/src/main/java/pl/wavesoftware/utils/stringify/lang/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @author Krzysztof Suszynski - * @since 30.04.18 - */ -@ParametersAreNonnullByDefault -package pl.wavesoftware.utils.stringify.lang; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/package-info.java index a2488c4..a15a1b8 100644 --- a/src/main/java/pl/wavesoftware/utils/stringify/package-info.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/package-info.java @@ -1,8 +1,27 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ + /** - * @author Krzysztof Suszyński - * @since 2018-04-18 + * @author Krzysztof Suszynski + * @since 1.0.0 */ +@ReturnTypesAreNonnullByDefault @ParametersAreNonnullByDefault package pl.wavesoftware.utils.stringify; +import pl.wavesoftware.eid.api.ReturnTypesAreNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/pl/wavesoftware/utils/stringify/spi/BeanFactory.java b/src/main/java/pl/wavesoftware/utils/stringify/spi/BeanFactory.java new file mode 100644 index 0000000..f9ef00d --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/spi/BeanFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.spi; + +/** + * Creates instances of classes based on a class. This is usually implemented by + * some DI container like Spring. + *

+ * Implementations can also implement optional interface {@link BootingAware} hinting + * library about readiness of this {@code BeanFactory}. + * + * @author Krzysztof Suszynski + * @since 1.0.0 + */ +public interface BeanFactory { + /** + * Creates an instance of a class + * + * @param contractClass a contract class to be created + * @param a type of a class + * @return an instance of a contract class + */ + T create(Class contractClass); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/spi/BootingAware.java b/src/main/java/pl/wavesoftware/utils/stringify/spi/BootingAware.java new file mode 100644 index 0000000..3fef3a7 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/spi/BootingAware.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.spi; + +/** + * If class implements this interface it might give hints whether it's ready to process + * calls or not. + * + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +public interface BootingAware { + /** + * Should return {@code true} if it'ssafe to process calls. + * + * @return true if booting has completed. + */ + boolean isReady(); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java b/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java new file mode 100644 index 0000000..35f6311 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.spi; + +import pl.wavesoftware.utils.stringify.api.Configuration; + +/** + * An interface to implement as a Java's {@link java.util.ServiceLoader ServiceLoader} + * mechanism. + *

+ * To do that, create on your classpath, a file: + *

META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
+ * + *

+ * In that file, place a fully qualified class name of your class that implements + * {@link Configurator} interface. It should be called first time you + * use an {@link pl.wavesoftware.utils.stringify.Stringify Stringify} to inspect + * an object. + * + * @see Configuration + * @author Krzysztof Suszynski + * @since 2.0.0 + */ +public interface Configurator { + /** + * Configures a library with various configuration options + * + * @param configuration a configuration + */ + void configure(Configuration configuration); +} diff --git a/src/main/java/pl/wavesoftware/utils/stringify/spi/package-info.java b/src/main/java/pl/wavesoftware/utils/stringify/spi/package-info.java new file mode 100644 index 0000000..434e785 --- /dev/null +++ b/src/main/java/pl/wavesoftware/utils/stringify/spi/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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. + */ + +/** + * @author Krzysztof Suszynski + * @since 20.04.18 + */ +@ReturnTypesAreNonnullByDefault +@ParametersAreNonnullByDefault +package pl.wavesoftware.utils.stringify.spi; + +import pl.wavesoftware.eid.api.ReturnTypesAreNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Account.java b/src/test/java/pl/wavesoftware/utils/stringify/Account.java index b261b52..45f2a63 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Account.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Account.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import java.sql.Blob; diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Acme.java b/src/test/java/pl/wavesoftware/utils/stringify/Acme.java new file mode 100755 index 0000000..e3321c6 --- /dev/null +++ b/src/test/java/pl/wavesoftware/utils/stringify/Acme.java @@ -0,0 +1,12 @@ +package pl.wavesoftware.utils.stringify; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import pl.wavesoftware.utils.stringify.api.Inspect; + +@Getter +@AllArgsConstructor +final class Acme { + @Inspect(conditionally = UnlessContainsSecret.class) + private String acme; +} diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Earth.java b/src/test/java/pl/wavesoftware/utils/stringify/Earth.java index 0fd433c..25012f5 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Earth.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Earth.java @@ -1,11 +1,27 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Data; import lombok.EqualsAndHashCode; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.Inspect; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ @Data diff --git a/src/test/java/pl/wavesoftware/utils/stringify/IsInDevelopment.java b/src/test/java/pl/wavesoftware/utils/stringify/IsInDevelopment.java index 9732ef0..204f55a 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/IsInDevelopment.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/IsInDevelopment.java @@ -1,7 +1,24 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.lang.Predicate; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; + +import java.util.function.Predicate; /** * @author Krzysztof Suszynski diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Moon.java b/src/test/java/pl/wavesoftware/utils/stringify/Moon.java index d335b60..db6560a 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Moon.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Moon.java @@ -1,16 +1,32 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.Inspect; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ @Data diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Person.java b/src/test/java/pl/wavesoftware/utils/stringify/Person.java index 775be3b..1b280d3 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Person.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Person.java @@ -1,9 +1,25 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Setter; -import pl.wavesoftware.utils.stringify.configuration.DisplayNull; -import pl.wavesoftware.utils.stringify.configuration.DoNotInspect; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.DisplayNull; +import pl.wavesoftware.utils.stringify.api.DoNotInspect; +import pl.wavesoftware.utils.stringify.api.Inspect; import java.util.List; diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Phase.java b/src/test/java/pl/wavesoftware/utils/stringify/Phase.java index 315f668..f0bec62 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Phase.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Phase.java @@ -1,7 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ enum Phase { diff --git a/src/test/java/pl/wavesoftware/utils/stringify/Planet.java b/src/test/java/pl/wavesoftware/utils/stringify/Planet.java index 4fc999f..719a36f 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/Planet.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/Planet.java @@ -1,14 +1,30 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Data; -import pl.wavesoftware.utils.stringify.configuration.DisplayNull; -import pl.wavesoftware.utils.stringify.configuration.DoNotInspect; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.DisplayNull; +import pl.wavesoftware.utils.stringify.api.DoNotInspect; +import pl.wavesoftware.utils.stringify.api.Inspect; import java.io.Serializable; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ @Data diff --git a/src/test/java/pl/wavesoftware/utils/stringify/PlanetSystem.java b/src/test/java/pl/wavesoftware/utils/stringify/PlanetSystem.java index ede0484..3f02c29 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/PlanetSystem.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/PlanetSystem.java @@ -1,13 +1,29 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Data; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.Inspect; import java.util.ArrayList; import java.util.List; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-19 */ @Data diff --git a/src/test/java/pl/wavesoftware/utils/stringify/ProductionEnvironment.java b/src/test/java/pl/wavesoftware/utils/stringify/ProductionEnvironment.java index 2503e69..c99fc6d 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/ProductionEnvironment.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/ProductionEnvironment.java @@ -1,7 +1,24 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.lang.Predicate; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; + +import java.util.function.Predicate; /** * @author Krzysztof Suszynski diff --git a/src/test/java/pl/wavesoftware/utils/stringify/SimpleUser.java b/src/test/java/pl/wavesoftware/utils/stringify/SimpleUser.java index 82ba440..8bc2a12 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/SimpleUser.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/SimpleUser.java @@ -1,8 +1,24 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Getter; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.DoNotInspect; +import pl.wavesoftware.utils.stringify.api.DoNotInspect; /** * @author Krzysztof Suszynski diff --git a/src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierIT.java b/src/test/java/pl/wavesoftware/utils/stringify/StringifyIT.java old mode 100644 new mode 100755 similarity index 73% rename from src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierIT.java rename to src/test/java/pl/wavesoftware/utils/stringify/StringifyIT.java index c2f95cb..b0f87e9 --- a/src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierIT.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/StringifyIT.java @@ -1,7 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; -import org.junit.ClassRule; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.infra.Blackhole; @@ -25,21 +41,21 @@ * @author Krzysztof Suszynski * @since 20.04.18 */ -public class ObjectStringifierIT { +public class StringifyIT { private static final int PERCENT = 100; private static final int OPERATIONS = 1000; - private static final Logger LOG = LoggerFactory.getLogger(ObjectStringifierIT.class); + private static final Logger LOG = LoggerFactory.getLogger(StringifyIT.class); private static final Planet TEST_OBJECT = new TestRepository().createTestPlanet(); - @ClassRule - public static final JmhCleaner cleaner = new JmhCleaner(ObjectStringifierIT.class);; + @RegisterExtension + static final JmhCleaner cleaner = new JmhCleaner(StringifyIT.class); @Test - public void doBenckmarking() throws RunnerException { + void doBenckmarking() throws RunnerException { Options opt = new OptionsBuilder() .include(this.getClass().getName() + ".*") .mode(Mode.Throughput) - .timeUnit(TimeUnit.MICROSECONDS) + .timeUnit(TimeUnit.MILLISECONDS) .operationsPerInvocation(OPERATIONS) .warmupTime(TimeValue.seconds(1)) .warmupIterations(2) @@ -49,8 +65,8 @@ public void doBenckmarking() throws RunnerException { .forks(1) .shouldFailOnError(true) .shouldDoGC(true) - .jvmArgs("-server", "-Xms256m", "-Xmx256m", - "-XX:PermSize=128m", "-XX:MaxPermSize=128m", "-XX:+UseParallelGC") + .jvmArgs("-Xms256m", "-Xmx256m", "-XX:+UseG1GC", "-XX:+AggressiveOpts", + "-XX:+OptimizeStringConcat", "-XX:+UseStringDeduplication") .build(); Runner runner = new Runner(opt); @@ -71,8 +87,8 @@ public void doBenckmarking() throws RunnerException { double eidTimes = eidScore / controlScore; - LOG.info("Control sample method time per operation: {} ops / µsec", controlScore); - LOG.info("#stringifier() method time per operation: {} ops / µsec", eidScore); + LOG.info("Control sample method time per operation: {} ops / ms", controlScore); + LOG.info("#stringifier() method time per operation: {} ops / ms", eidScore); LOG.info("{} and is {}%", eidTitle, eidTimes * PERCENT); assertThat(eidTimes) @@ -91,7 +107,7 @@ public void lombok(Blackhole bh) { @Benchmark public void stringifier(Blackhole bh) { for (int i = 0; i < OPERATIONS; i++) { - bh.consume(new ObjectStringifier(TEST_OBJECT).toString()); + bh.consume(Stringify.of(TEST_OBJECT).toString()); } } @@ -110,7 +126,7 @@ private static double getSpeedThreshold() { } private static RunResult getRunResultByName(Collection results, String name) { - String fullName = String.format("%s.%s", ObjectStringifierIT.class.getName(), name); + String fullName = String.format("%s.%s", StringifyIT.class.getName(), name); for (RunResult result : results) { if (result.getParams().getBenchmark().equals(fullName)) { return result; diff --git a/src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierTest.java b/src/test/java/pl/wavesoftware/utils/stringify/StringifyTest.java old mode 100644 new mode 100755 similarity index 54% rename from src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierTest.java rename to src/test/java/pl/wavesoftware/utils/stringify/StringifyTest.java index 10cb938..cccee51 --- a/src/test/java/pl/wavesoftware/utils/stringify/ObjectStringifierTest.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/StringifyTest.java @@ -1,67 +1,86 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.RequiredArgsConstructor; -import org.junit.Test; -import pl.wavesoftware.utils.stringify.configuration.AlwaysTruePredicate; -import pl.wavesoftware.utils.stringify.configuration.BeanFactory; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; -import pl.wavesoftware.utils.stringify.configuration.Mode; -import pl.wavesoftware.utils.stringify.lang.Predicate; -import pl.wavesoftware.utils.stringify.lang.Supplier; +import org.junit.jupiter.api.Test; +import pl.wavesoftware.utils.stringify.api.AlwaysTruePredicate; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.spi.BeanFactory; import java.lang.reflect.Field; import java.util.AbstractMap; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; /** - * @author Krzysztof Suszyński + * @author Krzysztof Suszynski * @since 2018-04-18 */ -public class ObjectStringifierTest { +class StringifyTest { private final TestRepository testRepository = new TestRepository(); @Test - public void testInQuietMode() { + void inQuietMode() { // given Planet planet = testRepository.createTestPlanet(); - ObjectStringifier stringifier = new ObjectStringifier(planet); - stringifier.setMode(Mode.QUIET); + Stringify stringifier = Stringify.of(planet); + stringifier.mode(Mode.QUIET); // when String repr = stringifier.toString(); // then - assertEquals(", moon=, dayOfYear=14, type='A'>", repr); + " \"1972\": [\"Apollo 16\",\"Apollo 17\"]}>, dayOfYear=14, type='A'>" + ); } @Test - public void testInPromiscuousMode() { + void inPromiscuousMode() { // given Planet planet = testRepository.createTestPlanet(); - ObjectStringifier stringifier = new ObjectStringifier(planet); + Stringify stringifier = Stringify.of(planet); // when String repr = stringifier.toString(); // then - assertEquals(", moon=, dayOfYear=14, type='A'>", repr); + " \"1972\": [\"Apollo 16\",\"Apollo 17\"]}>, dayOfYear=14, type='A'>" + ); } @Test - public void testByLombok() { + void byLombok() { // given Planet planet = testRepository.createTestPlanet(); @@ -69,15 +88,17 @@ public void testByLombok() { String repr = planet.toString(); // then - assertEquals("Earth(moon=Moon(phase=FULL_MOON, visits={1969=[Apollo 11, Apollo 12]," + - " 1971=[Apollo 14, Apollo 15], 1972=[Apollo 16, Apollo 17]}), dayOfYear=14, type=A)", repr); + assertThat(repr).isEqualTo( + "Earth(moon=Moon(phase=FULL_MOON, visits={1969=[Apollo 11, Apollo 12]," + + " 1971=[Apollo 14, Apollo 15], 1972=[Apollo 16, Apollo 17]}), dayOfYear=14, type=A)" + ); } @Test - public void testWithCustomPredicate() { + void withCustomPredicate() { // given SimpleUser user = testRepository.createTestSimpleUser(); - ObjectStringifier stringifier = new ObjectStringifier(user); + Stringify stringifier = Stringify.of(user); // when ProductionEnvironment.setProduction(true); @@ -86,11 +107,12 @@ public void testWithCustomPredicate() { String developmentResult = stringifier.toString(); // then - assertEquals("", productionResult); - assertEquals("", - developmentResult); + assertThat(productionResult).isEqualTo(""); + assertThat(developmentResult).isEqualTo( + "" + ); - assertTrue(new AlwaysTruePredicate().test( + assertThat(new AlwaysTruePredicate()).accepts( new InspectionPoint() { @Override public Field getField() { @@ -107,73 +129,103 @@ public Supplier getValueSupplier() { return null; } } - )); + ); } @Test - public void testWithCustomPredicateWithPredicateFactory() { + void withCustomPredicateWithPredicateFactory() { // given User user = testRepository.createTestUser(); IsInDevelopment isDevelopment = new IsInDevelopmentImpl(true); IsInDevelopment isProduction = new IsInDevelopmentImpl(false); BeanFactory productionBeanFactory = getBeanFactory(isProduction); BeanFactory developmentBeanFactory = getBeanFactory(isDevelopment); - ObjectStringifier stringifier = new ObjectStringifier(user); + Stringify stringifier = Stringify.of(user); // when - stringifier.setBeanFactory(productionBeanFactory); + stringifier.beanFactory(productionBeanFactory); String productionResult = stringifier.toString(); - stringifier.setBeanFactory(developmentBeanFactory); + stringifier.beanFactory(developmentBeanFactory); String developmentResult = stringifier.toString(); - stringifier.setMode(Mode.QUIET); - stringifier.setBeanFactory(developmentBeanFactory); + stringifier.mode(Mode.QUIET); + stringifier.beanFactory(developmentBeanFactory); String developmentQuietResult = stringifier.toString(); // then - assertEquals("", productionResult); - assertEquals("", developmentResult); - assertEquals("", developmentQuietResult); + assertThat(productionResult).isEqualTo(""); + assertThat(developmentResult).isEqualTo(""); + assertThat(developmentQuietResult).isEqualTo(""); } @Test - public void testOnPerson() { + void onPerson() { // given Person person = testRepository.createPerson(); - ObjectStringifier stringifier = new ObjectStringifier(person); + Stringify stringifier = Stringify.of(person); IsInDevelopment isProduction = new IsInDevelopmentImpl(false); BeanFactory productionBeanFactory = getBeanFactory(isProduction); - stringifier.setBeanFactory(productionBeanFactory); + stringifier.beanFactory(productionBeanFactory); // when String productionResult = stringifier.toString(); // then - assertEquals(", childs=[], account=⁂Lazy>", productionResult); + assertThat(productionResult).isEqualTo( + ", childs=[], account=⁂Lazy>" + ); } @Test - public void testOnPersonWithCustomPerdicateLogic() { + void onPersonWithCustomPerdicateLogic() { // given Person person = testRepository.createPerson(); - ObjectStringifier stringifier = new ObjectStringifier(person); - IsInDevelopment isInDevelopment = new IsInDevelopmentPredicate(new Predicate() { - @Override - public boolean test(Object value) { - return value instanceof String - && ((String) value).contains("!@#$"); - } - }); + Stringify stringifier = Stringify.of(person); + IsInDevelopment isInDevelopment = new IsInDevelopmentPredicate(value -> + value instanceof String + && ((String) value).contains("!@#$") + ); BeanFactory productionBeanFactory = getBeanFactory(isInDevelopment); - stringifier.setBeanFactory(productionBeanFactory); + stringifier.beanFactory(productionBeanFactory); // when String productionResult = stringifier.toString(); // then - assertEquals(", childs=[], " + - "account=⁂Lazy>", productionResult); + "account=⁂Lazy>" + ); + assertThat(stringifier).hasSize(52); + assertThat(stringifier.charAt(1)).isEqualTo('P'); + assertThat(stringifier.subSequence(1, 7)).isEqualTo("Person"); + } + + @Test + void fallbackToDefault() { + // given + Acme acme1 = new Acme("simple value"); + Stringify stringifier1 = Stringify.of(acme1); + Acme acme2 = new Acme("value with secret"); + Stringify stringifier2 = Stringify.of(acme2); + + try { + // when + TestBeanFactory.ready = true; + String result1 = stringifier1.toString(); + String result2 = stringifier2.toString(); + + // then + assertThat(result1).isEqualTo( + "" + ); + assertThat(result2).isEqualTo( + "" + ); + } finally { + TestBeanFactory.ready = false; + } } private static boolean inspectionPointValue(final InspectionPoint inspectionPoint, @@ -187,7 +239,7 @@ private static boolean inspectionPointValue(final InspectionPoint inspectionPoin private StaticBeanFactory getBeanFactory(IsInDevelopment isInDevelopmentFalse) { return new StaticBeanFactory( - new AbstractMap.SimpleImmutableEntry, Predicate>( + new AbstractMap.SimpleImmutableEntry<>( IsInDevelopment.class, isInDevelopmentFalse ) ); diff --git a/src/test/java/pl/wavesoftware/utils/stringify/TestBeanFactory.java b/src/test/java/pl/wavesoftware/utils/stringify/TestBeanFactory.java new file mode 100755 index 0000000..8c43443 --- /dev/null +++ b/src/test/java/pl/wavesoftware/utils/stringify/TestBeanFactory.java @@ -0,0 +1,21 @@ +package pl.wavesoftware.utils.stringify; + +import pl.wavesoftware.utils.stringify.spi.BeanFactory; +import pl.wavesoftware.utils.stringify.spi.BootingAware; + +final class TestBeanFactory implements BeanFactory, BootingAware { + + static boolean ready = false; + + @Override + public T create(Class contractClass) { + throw new UnsupportedOperationException( + "💩 This exception is expected to be thrown in JUnit" + ); + } + + @Override + public boolean isReady() { + return ready; + } +} diff --git a/src/test/java/pl/wavesoftware/utils/stringify/TestRepository.java b/src/test/java/pl/wavesoftware/utils/stringify/TestRepository.java index 19a0291..d067ff6 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/TestRepository.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/TestRepository.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import org.hibernate.collection.internal.PersistentList; diff --git a/src/test/java/pl/wavesoftware/utils/stringify/TestingConfigurator.java b/src/test/java/pl/wavesoftware/utils/stringify/TestingConfigurator.java new file mode 100755 index 0000000..19d1071 --- /dev/null +++ b/src/test/java/pl/wavesoftware/utils/stringify/TestingConfigurator.java @@ -0,0 +1,13 @@ +package pl.wavesoftware.utils.stringify; + +import pl.wavesoftware.utils.stringify.api.Configuration; +import pl.wavesoftware.utils.stringify.api.Mode; +import pl.wavesoftware.utils.stringify.spi.Configurator; + +public final class TestingConfigurator implements Configurator { + @Override + public void configure(Configuration configuration) { + configuration.mode(Mode.DEFAULT_MODE); + configuration.beanFactory(new TestBeanFactory()); + } +} diff --git a/src/test/java/pl/wavesoftware/utils/stringify/UnlessContainsSecret.java b/src/test/java/pl/wavesoftware/utils/stringify/UnlessContainsSecret.java new file mode 100755 index 0000000..c6b7c3f --- /dev/null +++ b/src/test/java/pl/wavesoftware/utils/stringify/UnlessContainsSecret.java @@ -0,0 +1,13 @@ +package pl.wavesoftware.utils.stringify; + +import pl.wavesoftware.utils.stringify.api.InspectionPoint; + +import java.util.function.Predicate; + +final class UnlessContainsSecret implements Predicate { + @Override + public boolean test(InspectionPoint inspectionPoint) { + Object value = inspectionPoint.getValueSupplier().get(); + return !value.toString().contains("secret"); + } +} diff --git a/src/test/java/pl/wavesoftware/utils/stringify/User.java b/src/test/java/pl/wavesoftware/utils/stringify/User.java index 594745f..ba17742 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/User.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/User.java @@ -1,8 +1,24 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify; import lombok.Getter; import lombok.RequiredArgsConstructor; -import pl.wavesoftware.utils.stringify.configuration.Inspect; +import pl.wavesoftware.utils.stringify.api.Inspect; /** * @author Krzysztof Suszynski diff --git a/src/test/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImplTest.java b/src/test/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImplTest.java index 1cdcb75..53381b4 100644 --- a/src/test/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImplTest.java +++ b/src/test/java/pl/wavesoftware/utils/stringify/impl/InspectionPointImplTest.java @@ -1,7 +1,23 @@ +/* + * Copyright 2018-2019 Wave Software + * + * 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 pl.wavesoftware.utils.stringify.impl; -import org.junit.Test; -import pl.wavesoftware.utils.stringify.configuration.InspectionPoint; +import org.junit.jupiter.api.Test; +import pl.wavesoftware.utils.stringify.api.InspectionPoint; import java.lang.reflect.Field; @@ -11,10 +27,10 @@ * @author Krzysztof Suszynski * @since 30.04.18 */ -public class InspectionPointImplTest { +class InspectionPointImplTest { @Test - public void testGetValueSupplier() throws NoSuchFieldException { + void testGetValueSupplier() throws NoSuchFieldException { // given Sample sample = new Sample(); sample.ala = "ma"; diff --git a/src/test/resources/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator b/src/test/resources/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator new file mode 100755 index 0000000..0ee09f9 --- /dev/null +++ b/src/test/resources/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator @@ -0,0 +1 @@ +pl.wavesoftware.utils.stringify.TestingConfigurator diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties deleted file mode 100644 index 821be00..0000000 --- a/src/test/resources/simplelogger.properties +++ /dev/null @@ -1,5 +0,0 @@ -# SLF4J's SimpleLogger configuration file -org.slf4j.simpleLogger.defaultLogLevel=info -org.slf4j.simpleLogger.showThreadName=false -org.slf4j.simpleLogger.showLogName=false -org.slf4j.simpleLogger.showShortLogName=false From 1417028291de4557f0a244d6bdeda08fa4bcbc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Suszy=C5=84ski?= Date: Fri, 5 Jul 2019 12:35:27 +0200 Subject: [PATCH 2/3] (maint) Switch version to 2.0.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 252dc63..74d9abc 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ pl.wavesoftware.utils stringify-object - 1.0.3-SNAPSHOT + 2.0.0-SNAPSHOT jar Stringify Object for Java From 356aa34fa316728a3a5674d80deaec70df59273a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Suszy=C5=84ski?= Date: Fri, 5 Jul 2019 13:23:08 +0200 Subject: [PATCH 3/3] (maint) Update documentation on how to use configuration --- README.adoc | 230 ++++++++++++++++++ README.md | 103 -------- .../utils/stringify/Stringify.java | 67 +++++ .../utils/stringify/api/Configuration.java | 24 +- .../utils/stringify/spi/Configurator.java | 75 +++++- 5 files changed, 379 insertions(+), 120 deletions(-) create mode 100644 README.adoc delete mode 100644 README.md mode change 100644 => 100755 src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java mode change 100644 => 100755 src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..d1cf79e --- /dev/null +++ b/README.adoc @@ -0,0 +1,230 @@ +== Stringify Object for Java + +https://travis-ci.org/wavesoftware/java-stringify-object[image:https://travis-ci.org/wavesoftware/java-stringify-object.svg?branch=master[Build +Status]] +https://sonar.wavesoftware.pl/dashboard/index/pl.wavesoftware.utils:stringify-object[image:https://sonar.wavesoftware.pl/api/badges/gate?key=pl.wavesoftware.utils:stringify-object[Quality +Gate]] +https://coveralls.io/github/wavesoftware/java-stringify-object?branch=master[image:https://coveralls.io/repos/github/wavesoftware/java-stringify-object/badge.svg?branch=master[Coverage +Status]] +https://bintray.com/bintray/jcenter/pl.wavesoftware.utils%3Astringify-object[image:https://img.shields.io/maven-central/v/pl.wavesoftware.utils/stringify-object.svg[Maven +Central]] + +A utility to safely inspect any Java Object as String representation. +It's best to be used with domain model (also with JPA entities) with +intention to dump those entities as text to log files. + +It runs in two modes: `+PROMISCUOUS+` (by default) and `+QUIET+`. In +`+PROMISCUOUS+` mode every defined field is automatically inspected, +unless the field is annotated with `+@DoNotInspect+` annotation. In +`+QUIET+` mode only fields annotated with `+@Inspect+` will gets +inspected. + +This library has proper support for object graph cycles, and JPA +(Hibernate) lazy loaded elements. + +=== Usage + +==== In Promiscuous mode + +[source,java] +---- +// In PROMISCUOUS mode define fields to exclude +class Person { + private int id; + @DisplayNull + private Person parent; + private List childs; + private Account account; + @Inspect(conditionally = IsInDevelopment.class) + private String password; + @DoNotInspect + private String ignored; +} + +// inspect an object +List people = query.getResultList(); +Stringify stringify = Stringify.of(people); +stringify.mode(Mode.PROMISCUOUS); +// stringify.beanFactory(...); +assert ", childs=[], " + + "account=⁂Lazy>".equals(stringify.toString()); +---- + +==== In Quiet mode + +[source,java] +---- +// In QUIET mode define fields to inspect +class Person { + @Inspect private int id; + @Inspect @DisplayNull private Person parent; + @Inspect private List childs; + @Inspect private Account account; + private String ignored; +} + +// inspect an object +List people = query.getResultList(); +Stringify stringify = Stringify.of(people); +stringify.mode(Mode.QUIET); +assert ", childs=[], " + + "account=⁂Lazy>".equals(stringify.toString()); +---- + +=== Features + +* String representation of any Java class in two modes `+PROMISCUOUS+` +and `+QUIET+` +* Fine tuning of which fields to display +* Support for cycles in object graph - `+(↻)+` is displayed instead +* Support for Hibernate lazy loaded entities - `+⁂Lazy+` is displayed +instead + +[[vs-lombok-tostring]] +=== vs. Lombok @ToString + +Stringify Object for Java is designed for *slightly different* use case +then Lombok. + +Lombok `+@ToString+` is designed to quickly inspect fields of simple +objects by generating static simple implementation of this mechanism. + +Stringify Object for Java is designed to inspect complex objects that +can have cycles and can be managed by JPA provider like Hibernate +(introducing Lazy Loading problems). + +==== Pros of Lombok vs Stringify Object + +* Lombok is *fast* - it's statically generated code without using +Reflection API. +* Lombok is *easy* - it's zero configuration in most cases. + +==== Cons of Lombok vs Stringify Object + +* Lombok can't *detect cycles* is object graph, which implies +`+StackOverflowException+` being thrown in that case +* Lombok can't detect a *lazy loaded entities*, which leads to force +loading it from JPA by invoking SQL statements. It's typical *n+1 +problem*, but with nasty consequences - your `+toString()+` method is +invoking SQL without your knowledge!! + +=== Configuration + +Configuration is done in two ways: declarative - using Java's service +loader mechanism, and programmatic. + +==== Configuration using Service Loader + +A `+Configurator+` interface is intended to be implemented in user code, +and assigned to https://www.baeldung.com/java-spi[Service Loader] +mechanism. + +To do that, create on your classpath, a file: + +`+/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator+` + +In that file, place a fully qualified class name of your class that +implements `+Configurator+` interface. It should be called first time +you use an Stringify to inspect an object: + +.... +# classpath:/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator +org.acmecorp.StringifyConfigurator +.... + +Then implement that class in your code: + +[source,java] +---- +package org.acmecorp; + +import pl.wavesoftware.utils.stringify.api.Configuration; +import pl.wavesoftware.utils.stringify.spi.Configurator; + +public final class StringifyConfigurator implements Configurator { + + @Override + public void configure(Configuration configuration) { + configuration.beanFactory(new SpringBeanFactory()); + } +} +---- + +with example Spring based BeanFactory: + +[source,java] +---- +package org.acmecorp; + +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; + +import pl.wavesoftware.utils.stringify.spi.BeanFactory; +import pl.wavesoftware.utils.stringify.spi.BootingAware; + +@Configuration +class SpringBeanFactory implements BeanFactory, BootingAware { + private static ApplicationContext context; + + @EventListener(ContextRefreshedEvent.class) + void onRefresh(ContextRefreshedEvent event) { + SpringBeanFactory.context = event.getApplicationContext(); + } + + @Override + public T create(Class contractClass) { + return SpringBeanFactory.context.getBean(contractClass); + } + + @Override + public boolean isReady() { + return SpringBeanFactory.context != null; + } +} +---- + +==== Programmatic configuration + +You can also fine tune you configuration on instance level - using +methods available at `+Stringify+` interface: + +[source,java] +---- +// given +BeanFactory beanFactory = createBeanFactory(); +Person person = createPerson(); + +// then +Stringify stringifier = Stringify.of(person); +stringifier + .beanFactory(beanFactory) + .mode(Mode.QUIET) + .stringify(); +---- + +=== Dependencies + +* Java >= 8 +* https://github.com/wavesoftware/java-eid-exceptions[EID Exceptions] +library + +==== Contributing + +Contributions are welcome! + +To contribute, follow the standard +http://danielkummer.github.io/git-flow-cheatsheet/[git flow] of: + +. Fork it +. Create your feature branch +(`+git checkout -b feature/my-new-feature+`) +. Commit your changes (`+git commit -am 'Add some feature'+`) +. Push to the branch (`+git push origin feature/my-new-feature+`) +. Create new Pull Request + +Even if you can't contribute code, if you have an idea for an +improvement please open an +https://github.com/wavesoftware/java-stringify-object/issues[issue]. diff --git a/README.md b/README.md deleted file mode 100644 index 5c633b4..0000000 --- a/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Stringify Object for Java - -[![Build Status](https://travis-ci.org/wavesoftware/java-stringify-object.svg?branch=master)](https://travis-ci.org/wavesoftware/java-stringify-object) [![Quality Gate](https://sonar.wavesoftware.pl/api/badges/gate?key=pl.wavesoftware.utils:stringify-object)](https://sonar.wavesoftware.pl/dashboard/index/pl.wavesoftware.utils:stringify-object) [![Coverage Status](https://coveralls.io/repos/github/wavesoftware/java-stringify-object/badge.svg?branch=master)](https://coveralls.io/github/wavesoftware/java-stringify-object?branch=master) [![Maven Central](https://img.shields.io/maven-central/v/pl.wavesoftware.utils/stringify-object.svg)](https://bintray.com/bintray/jcenter/pl.wavesoftware.utils%3Astringify-object) - - -A utility to safely inspect any Java Object as String representation. It's best to be used with domain model (also with JPA entities) with intention to dump those entities as text to log files. - -It runs in two modes: `PROMISCUOUS` (by default) and `QUIET`. In `PROMISCUOUS` mode every defined field is automatically inspected, unless the field is annotated with `@DoNotInspect` annotation. -In `QUIET` mode only fields annotated with `@Inspect` will gets inspected. - -This library has proper support for object graph cycles, and JPA (Hibernate) lazy loaded elements. - - ## Usage - - ### In Promiscuous mode - -```java -// In PROMISCUOUS mode define fields to exclude -class Person { - private int id; - @DisplayNull - private Person parent; - private List childs; - private Account account; - @Inspect(conditionally = IsInDevelopment.class) - private String password; - @DoNotInspect - private String ignored; -} - -// inspect an object -List people = query.getResultList(); -ObjectStringifier stringifier = new ObjectStringifier(people); -stringifier.setMode(Mode.PROMISCUOUS); -// stringifier.setBeanFactory(...); -assert ", childs=[], " - + "account=⁂Lazy>".equals(stringifier.toString()); -``` - - ### In Quiet mode -```java -// In QUIET mode define fields to inspect -class Person { - @Inspect private int id; - @Inspect @DisplayNull private Person parent; - @Inspect private List childs; - @Inspect private Account account; - private String ignored; -} - -// inspect an object -List people = query.getResultList(); -ObjectStringifier stringifier = new ObjectStringifier(people); -stringifier.setMode(Mode.QUIET); -assert ", childs=[], " - + "account=⁂Lazy>".equals(stringifier.toString()); -``` - -## Features - - * String representation of any Java class in two modes `PROMISCUOUS` and `QUIET` - * Fine tuning of which fields to display - * Support for cycles in object graph - `(↻)` is displayed instead - * Support for Hibernate lazy loaded entities - `⁂Lazy` is displayed instead - -## vs. Lombok @ToString - -Stringify Object for Java is designed for **slightly different** use case then Lombok. - -Lombok `@ToString` is designed to quickly inspect fields of simple objects by generating static simple implementation of this mechanism. - -Stringify Object for Java is designed to inspect complex objects that can have cycles and can be managed by JPA provider like Hibernate (introducing Lazy Loading problems). - -#### Pros of Lombok vs Stringify Object - - * Lombok is **fast** - it's statically generated code without using Reflection API. - * Lombok is **easy** - it's zero configuration in most cases. - -#### Cons of Lombok vs Stringify Object - - * Lombok can't **detect cycles** is object graph, which implies `StackOverflowException` being thrown in that case - * Lombok can't detect a **lazy loaded entities**, which leads to force loading it from JPA by invoking SQL statements. It's typical **n+1 problem**, but with nasty consequences - your `toString()` method is invoking SQL without your knowledge!! - -## Dependencies - - * Java >= 7 - * [EID Exceptions](https://github.com/wavesoftware/java-eid-exceptions) library - -### Contributing - -Contributions are welcome! - -To contribute, follow the standard [git flow](http://danielkummer.github.io/git-flow-cheatsheet/) of: - -1. Fork it -1. Create your feature branch (`git checkout -b feature/my-new-feature`) -1. Commit your changes (`git commit -am 'Add some feature'`) -1. Push to the branch (`git push origin feature/my-new-feature`) -1. Create new Pull Request - -Even if you can't contribute code, if you have an idea for an improvement please open an [issue](https://github.com/wavesoftware/java-stringify-object/issues). diff --git a/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java b/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java index b1aeed4..fb76b4e 100755 --- a/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/Stringify.java @@ -23,6 +23,7 @@ import pl.wavesoftware.utils.stringify.spi.BeanFactory; /** + *

Stringify Object for Java

* A utility to safely inspect any Java Object as String representation. It's best to be * used with domain model (also with JPA entities) with intention to dump those entities * as text to log files. @@ -35,6 +36,72 @@ * This library has proper support for object graph cycles, and JPA (Hibernate) * lazy loaded elements. * + *

Usage

+ *
+ * // In PROMISCUOUS mode (by default) define fields to exclude
+ * class Person {
+ *   private int id;
+ *   @DisplayNull
+ *   private Person parent;
+ *   private List<Person> childs;
+ *   private Account account;
+ *   @Inspect(conditionally = IsInDevelopment.class)
+ *   private String password;
+ *   @DoNotInspect
+ *   private String ignored;
+ * }
+ *
+ * // inspect an object
+ * List<Person> people = query.getResultList();
+ * Stringify stringify = Stringify.of(people);
+ * // stringify.beanFactory(...);
+ * assert "<Person id=15, parent=<Person id=16, parent=null, "
+ *  + "childs=[(↻)], account=⁂Lazy>, childs=[], "
+ *  + "account=⁂Lazy>".equals(stringify.toString());
+ * 
+ * + * + *

Features

+ *
    + *
  • String representation of any Java class in two modes {@code PROMISCUOUS} + * and {@code QUIET}
  • + *
  • Fine tuning of which fields to display
  • + *
  • Support for cycles in object graph - {@code (↻)} is displayed instead
  • + *
  • Support for Hibernate lazy loaded entities - {@code ⁂Lazy} is displayed + * instead
  • + *
+ * + *

vs. Lombok @ToString

+ * + * Stringify Object for Java is designed for slightly different use case + * then Lombok. + *

+ * Lombok {@code @ToString} is designed to quickly inspect fields of simple objects by + * generating static simple implementation of this mechanism. + * + *

+ * Stringify Object for Java is designed to inspect complex objects that can have cycles + * and can be managed by JPA provider like Hibernate (introducing Lazy Loading problems). + * + *

Pros of Lombok vs Stringify Object

+ * + *
    + *
  • Lombok is fast - it's statically generated code + * without using Reflection API.
  • + *
  • Lombok is easy - it's zero configuration in most cases.
  • + *
+ * + *

Cons of Lombok vs Stringify Object

+ * + *
    + *
  • Lombok can't detect cycles is object graph, which implies + * {@code StackOverflowException} being thrown in that case
  • + *
  • Lombok can't detect a lazy loaded entities, which leads to + * force loading it from JPA by invoking SQL statements. It's typical n+1 + * problem, but with nasty consequences - your {@code toString()} method is + * invoking SQL without your knowledge!!
  • + *
+ * * @author Krzysztof Suszynski * @since 1.0.0 */ diff --git a/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java b/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java old mode 100644 new mode 100755 index 87c6ad3..f80642d --- a/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/api/Configuration.java @@ -22,19 +22,25 @@ /** * A interface that represents a configuration options for this library *

- * To use that one should implement {@link Configurator} with Java's - * {@link java.util.ServiceLoader ServiceLoader} mechanism. - *

- * To do that, create on your classpath, a file: - *

META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
+ * To configure this library you either use: + *
    + *
  • declarative way - using Java's {@link java.util.ServiceLoader ServiceLoader} + * mechanism,
  • + *
  • or programmatic way.
  • + *
* *

- * In that file, place a fully qualified class name of your class that implements - * {@link Configurator} interface. It should be called first time you - * use an {@link pl.wavesoftware.utils.stringify.Stringify Stringify} to inspect - * an object. + * On how to use declarative way consult Javadoc of {@link Configurator}. + *

+ * To use programmatic way, just invoke configuration methods on instance of + * {@link pl.wavesoftware.utils.stringify.Stringify Stringify} object. + *

+ * {@link BeanFactory} interface can be used to create instances of classes, declared + * in annotations used to define inspection rules. * * @see Configurator + * @see BeanFactory + * @see pl.wavesoftware.utils.stringify.Stringify Stringify * @author Krzysztof Suszynski * @since 2.0.0 */ diff --git a/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java b/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java old mode 100644 new mode 100755 index 35f6311..5b03439 --- a/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java +++ b/src/main/java/pl/wavesoftware/utils/stringify/spi/Configurator.java @@ -18,19 +18,78 @@ import pl.wavesoftware.utils.stringify.api.Configuration; +import java.util.ServiceLoader; + /** - * An interface to implement as a Java's {@link java.util.ServiceLoader ServiceLoader} - * mechanism. + * A {@code Configurator} interface is intended to be implemented in user code, and + * assigned to Service Loader mechanism. *

* To do that, create on your classpath, a file: - *

META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
* - *

+ *

+ * /META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
+ * 
+ * * In that file, place a fully qualified class name of your class that implements - * {@link Configurator} interface. It should be called first time you - * use an {@link pl.wavesoftware.utils.stringify.Stringify Stringify} to inspect - * an object. - * + * {@code Configurator} interface. It should be called first time you use an Stringify + * to inspect an object: + * + *
+ * # classpath:/META-INF/services/pl.wavesoftware.utils.stringify.spi.Configurator
+ * org.acmecorp.StringifyConfigurator
+ * 
+ * + * Then implement that class in your code: + * + *
+ * package org.acmecorp;
+ *
+ * import pl.wavesoftware.utils.stringify.api.Configuration;
+ * import pl.wavesoftware.utils.stringify.spi.Configurator;
+ *
+ * public final class StringifyConfigurator implements Configurator {
+ *
+ *   @Override
+ *   public void configure(Configuration configuration) {
+ *     configuration.beanFactory(new SpringBeanFactory());
+ *   }
+ * }
+ * 
+ * + * with example Spring based BeanFactory: + * + *
+ * package org.acmecorp;
+ *
+ * import org.springframework.context.event.ContextRefreshedEvent;
+ * import org.springframework.context.ApplicationContext;
+ * import org.springframework.context.annotation.Configuration;
+ *
+ * import pl.wavesoftware.utils.stringify.spi.BeanFactory;
+ * import pl.wavesoftware.utils.stringify.spi.BootingAware;
+ *
+ * @Configuration
+ * class SpringBeanFactory implements BeanFactory, BootingAware {
+ *   private static ApplicationContext context;
+ *
+ *   @EventListener(ContextRefreshedEvent.class)
+ *   void onRefresh(ContextRefreshedEvent event) {
+ *     SpringBeanFactory.context = event.getApplicationContext();
+ *   }
+ *
+ *   @Override
+ *   public <T> T create(Class<T> contractClass) {
+ *     return SpringBeanFactory.context.getBean(contractClass);
+ *   }
+ *
+ *   @Override
+ *   public boolean isReady() {
+ *     return SpringBeanFactory.context != null;
+ *   }
+ * }
+ * 
+ * + * @see ServiceLoader * @see Configuration * @author Krzysztof Suszynski * @since 2.0.0