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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
== Stringify Object for Java
= 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]]
Expand All @@ -22,20 +22,20 @@ inspected.
This library has proper support for object graph cycles, and JPA
(Hibernate) lazy loaded elements.

=== Usage
== Usage

==== In Promiscuous mode
=== In Promiscuous mode

[source,java]
----
// In PROMISCUOUS mode define fields to exclude
class Person {
private int id;
@DisplayNull
@DisplayNull // <1>
private Person parent;
private List<Person> childs;
private Account account;
@Inspect(conditionally = IsInDevelopment.class)
@Inspect(conditionally = IsInDevelopment.class) // <2>
private String password;
@DoNotInspect
private String ignored;
Expand All @@ -46,12 +46,15 @@ List<Person> people = query.getResultList();
Stringify stringify = Stringify.of(people);
stringify.mode(Mode.PROMISCUOUS);
// stringify.beanFactory(...);
assert "<Person id=15, parent=<Person id=16, parent=null, "
assert "[<Person id=15, parent=<Person id=16, parent=null, "
+ "childs=[(↻)], account=⁂Lazy>, childs=[], "
+ "account=⁂Lazy>".equals(stringify.toString());
+ "account=⁂Lazy>]".equals(stringify.toString());
----

==== In Quiet mode
<1> Configures a field inspection to show null values
<2> Inspects a field, but only if given predicate returns `true`

=== In Quiet mode

[source,java]
----
Expand All @@ -68,12 +71,12 @@ class Person {
List<Person> people = query.getResultList();
Stringify stringify = Stringify.of(people);
stringify.mode(Mode.QUIET);
assert "<Person id=15, parent=<Person id=16, parent=null, "
assert "[<Person id=15, parent=<Person id=16, parent=null, "
+ "childs=[(↻)], account=⁂Lazy>, childs=[], "
+ "account=⁂Lazy>".equals(stringify.toString());
+ "account=⁂Lazy>]".equals(stringify.toString());
----

=== Features
== Features

* String representation of any Java class in two modes `+PROMISCUOUS+`
and `+QUIET+`
Expand All @@ -83,7 +86,7 @@ and `+QUIET+`
instead

[[vs-lombok-tostring]]
=== vs. Lombok @ToString
== vs. Lombok @ToString

Stringify Object for Java is designed for *slightly different* use case
then Lombok.
Expand All @@ -95,13 +98,13 @@ 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
=== 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
=== Cons of Lombok vs Stringify Object

* Lombok can't *detect cycles* is object graph, which implies
`+StackOverflowException+` being thrown in that case
Expand All @@ -110,12 +113,12 @@ 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

Configuration is done in two ways: declarative - using Java's service
loader mechanism, and programmatic.

==== Configuration using Service Loader
=== 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]
Expand Down Expand Up @@ -186,7 +189,7 @@ class SpringBeanFactory implements BeanFactory, BootingAware {
}
----

==== Programmatic configuration
=== Programmatic configuration

You can also fine tune you configuration on instance level - using
methods available at `+Stringify+` interface:
Expand All @@ -205,13 +208,13 @@ stringifier
.stringify();
----

=== Dependencies
== Dependencies

* Java >= 8
* https://github.com/wavesoftware/java-eid-exceptions[EID Exceptions]
library

==== Contributing
=== Contributing

Contributions are welcome!

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/pl/wavesoftware/utils/stringify/Stringify.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@
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.api.Namespace;
import pl.wavesoftware.utils.stringify.api.Store;
import pl.wavesoftware.utils.stringify.impl.DefaultStringify;
import pl.wavesoftware.utils.stringify.spi.BeanFactory;
import pl.wavesoftware.utils.stringify.spi.theme.Theme;

import java.util.function.Consumer;

/**
* <h1>Stringify Object for Java</h1>
Expand Down Expand Up @@ -129,4 +134,10 @@ static Stringify of(Object object) {

@Override
Stringify beanFactory(BeanFactory beanFactory);

@Override
Stringify theme(Theme theme);

@Override
Stringify store(Namespace namespace, Consumer<Store> storeConsumer);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import pl.wavesoftware.utils.stringify.spi.Configurator;
import pl.wavesoftware.utils.stringify.spi.theme.Theme;

import java.util.function.Consumer;

/**
* A interface that represents a configuration options for this library
* <p>
Expand All @@ -39,10 +41,10 @@
* {@link BeanFactory} interface can be used to create instances of classes, declared
* in annotations used to define inspection rules.
*
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
* @see Configurator
* @see BeanFactory
* @see pl.wavesoftware.utils.stringify.Stringify Stringify
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
* @since 2.0.0
*/
public interface Configuration {
Expand All @@ -69,4 +71,13 @@ public interface Configuration {
* @return a self reference
*/
Configuration theme(Theme theme);

/**
* A named general purpose configuration
*
* @param namespace a namespace oa a store to configure
* @param storeConsumer a consumer that can modify a named store
* @return a self reference
*/
Configuration store(Namespace namespace, Consumer<Store> storeConsumer);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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;

/**
* An indentation of output that can be used by
* {@link pl.wavesoftware.utils.stringify.spi.theme.Theme Theme} elements to prepare
* pretty print.
*
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
* @since 2.0.0
*/
public interface IndentationControl {
/**
* Current level of indentation.
*
* @return an indentation level
*/
int current();

/**
* Increments current level of indentation.
*/
void increment();

/**
* Decrements current level of indentation.
*/
void decrement();

/**
* Calculates a indent text based on a indent value and current level
*
* @param indent a text representation of indent
* @return a complete indent
*/
default CharSequence indent(CharSequence indent) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < current(); i++) {
builder.append(indent);
}
return builder;
}
}
Original file line number Diff line number Diff line change
@@ -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.api;

/**
* An context of current inspection.
*
* @author <a href="mailto:krzysztof.suszynski@wavesoftware.pl">Krzysztof Suszynski</a>
* @since 2.0.0
*/
public interface InspectionContext {
/**
* Control of indentation.
*
* @return a control of indentation
*/
IndentationControl indentationControl();

/**
* A named, general purpose store
*
* @param namespace a namespace of a store
* @return a store
*/
Store store(Namespace namespace);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@

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.
* Represents a inspection point in some object, that is a field with value.
*
* @author <a href="mailto:krzysztof.suszynski@coi.gov.pl">Krzysztof Suszynski</a>
* @since 1.0.0
*/
public interface InspectionPoint {
/**
* Get field representation of inspection point
* @return a field
* Get a field value supplier
*
* @return a supplier of a field value
*/
Field getField();
Supplier<Object> getValue();

/**
* Get object that contains this inspection point
* @return an object
* Get a type of a field
* @return a type of a field
*/
Object getContainingObject();
Supplier<Class<?>> getType();

/**
* Get a field value supplier
* Gets a context object associated with this inspection point
*
* @return a supplier of a field value
* @return a context object
*/
Supplier<Object> getValueSupplier();
InspectionContext getContext();
}
Loading