org.hibernate.loader.plan.build.spi.ReturnGraphTreePrinter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.loader.plan.build.spi;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import org.hibernate.loader.plan.spi.BidirectionalEntityReference;
import org.hibernate.loader.plan.spi.CollectionAttributeFetch;
import org.hibernate.loader.plan.spi.CollectionFetchableElement;
import org.hibernate.loader.plan.spi.CollectionFetchableIndex;
import org.hibernate.loader.plan.spi.CollectionReference;
import org.hibernate.loader.plan.spi.CompositeFetch;
import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.EntityReturn;
import org.hibernate.loader.plan.spi.Fetch;
import org.hibernate.loader.plan.spi.FetchSource;
import org.hibernate.loader.plan.spi.Return;
import org.hibernate.loader.plan.spi.ScalarReturn;
/**
* Prints a {@link Return} graph as a tree structure.
*
* Intended for use in debugging, logging, etc.
*
* @author Steve Ebersole
*/
public class ReturnGraphTreePrinter {
/**
* Singleton access
*/
public static final ReturnGraphTreePrinter INSTANCE = new ReturnGraphTreePrinter();
private ReturnGraphTreePrinter() {
}
public String asString(Return rootReturn) {
return asString( rootReturn, 0 );
}
public String asString(Return rootReturn, int depth) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream( byteArrayOutputStream );
write( rootReturn, depth, ps );
ps.flush();
return new String( byteArrayOutputStream.toByteArray() );
}
public void write(Return rootReturn, PrintStream printStream) {
write( rootReturn, new PrintWriter( printStream ) );
}
public void write(Return rootReturn, int depth, PrintStream printStream) {
write( rootReturn, depth, new PrintWriter( printStream ) );
}
// todo : see ASTPrinter and try to apply its awesome tree structuring here.
// I mean the stuff it does with '|' and '\\-' and '+-' etc as
// prefixes for the tree nodes actual text to visually render the tree
public void write(Return rootReturn, PrintWriter printWriter) {
write( rootReturn, 0, printWriter );
}
public void write(Return rootReturn, int depth, PrintWriter printWriter) {
if ( rootReturn == null ) {
printWriter.println( "Return is null!" );
return;
}
printWriter.write( TreePrinterHelper.INSTANCE.generateNodePrefix( depth ) );
if ( ScalarReturn.class.isInstance( rootReturn ) ) {
printWriter.println( extractDetails( (ScalarReturn) rootReturn ) );
}
else if ( EntityReturn.class.isInstance( rootReturn ) ) {
final EntityReturn entityReturn = (EntityReturn) rootReturn;
printWriter.println( extractDetails( entityReturn ) );
writeEntityReferenceFetches( entityReturn, depth+1, printWriter );
}
else if ( CollectionReference.class.isInstance( rootReturn ) ) {
final CollectionReference collectionReference = (CollectionReference) rootReturn;
printWriter.println( extractDetails( collectionReference ) );
writeCollectionReferenceFetches( collectionReference, depth+1, printWriter );
}
printWriter.flush();
}
private String extractDetails(ScalarReturn rootReturn) {
return String.format(
"%s(name=%s, type=%s)",
rootReturn.getClass().getSimpleName(),
rootReturn.getName(),
rootReturn.getType().getName()
);
}
private String extractDetails(EntityReference entityReference) {
return String.format(
"%s(entity=%s, querySpaceUid=%s, path=%s)",
entityReference.getClass().getSimpleName(),
entityReference.getEntityPersister().getEntityName(),
entityReference.getQuerySpaceUid(),
entityReference.getPropertyPath().getFullPath()
);
}
private String extractDetails(CollectionReference collectionReference) {
// todo : include some form of parameterized type signature? i.e., List, Set, etc
return String.format(
"%s(collection=%s, querySpaceUid=%s, path=%s)",
collectionReference.getClass().getSimpleName(),
collectionReference.getCollectionPersister().getRole(),
collectionReference.getQuerySpaceUid(),
collectionReference.getPropertyPath().getFullPath()
);
}
private String extractDetails(CompositeFetch compositeFetch) {
return String.format(
"%s(composite=%s, querySpaceUid=%s, path=%s)",
compositeFetch.getClass().getSimpleName(),
compositeFetch.getFetchedType().getReturnedClass().getName(),
compositeFetch.getQuerySpaceUid(),
compositeFetch.getPropertyPath().getFullPath()
);
}
private void writeEntityReferenceFetches(EntityReference entityReference, int depth, PrintWriter printWriter) {
if ( BidirectionalEntityReference.class.isInstance( entityReference ) ) {
return;
}
if ( entityReference.getIdentifierDescription().hasFetches() ) {
printWriter.println( TreePrinterHelper.INSTANCE.generateNodePrefix( depth ) + "(entity id) " );
writeFetches( ( (FetchSource) entityReference.getIdentifierDescription() ).getFetches(), depth+1, printWriter );
}
writeFetches( entityReference.getFetches(), depth, printWriter );
}
private void writeFetches(Fetch[] fetches, int depth, PrintWriter printWriter) {
for ( Fetch fetch : fetches ) {
writeFetch( fetch, depth, printWriter );
}
}
private void writeFetch(Fetch fetch, int depth, PrintWriter printWriter) {
printWriter.print( TreePrinterHelper.INSTANCE.generateNodePrefix( depth ) );
if ( EntityFetch.class.isInstance( fetch ) ) {
final EntityFetch entityFetch = (EntityFetch) fetch;
printWriter.println( extractDetails( entityFetch ) );
writeEntityReferenceFetches( entityFetch, depth+1, printWriter );
}
else if ( CompositeFetch.class.isInstance( fetch ) ) {
final CompositeFetch compositeFetch = (CompositeFetch) fetch;
printWriter.println( extractDetails( compositeFetch ) );
writeCompositeFetchFetches( compositeFetch, depth+1, printWriter );
}
else if ( CollectionAttributeFetch.class.isInstance( fetch ) ) {
final CollectionAttributeFetch collectionFetch = (CollectionAttributeFetch) fetch;
printWriter.println( extractDetails( collectionFetch ) );
writeCollectionReferenceFetches( collectionFetch, depth+1, printWriter );
}
}
private void writeCompositeFetchFetches(CompositeFetch compositeFetch, int depth, PrintWriter printWriter) {
writeFetches( compositeFetch.getFetches(), depth, printWriter );
}
private void writeCollectionReferenceFetches(
CollectionReference collectionReference,
int depth,
PrintWriter printWriter) {
final CollectionFetchableIndex indexGraph = collectionReference.getIndexGraph();
if ( indexGraph != null ) {
printWriter.print( TreePrinterHelper.INSTANCE.generateNodePrefix( depth ) + "(collection index) " );
if ( EntityReference.class.isInstance( indexGraph ) ) {
final EntityReference indexGraphAsEntityReference = (EntityReference) indexGraph;
printWriter.println( extractDetails( indexGraphAsEntityReference ) );
writeEntityReferenceFetches( indexGraphAsEntityReference, depth+1, printWriter );
}
else if ( CompositeFetch.class.isInstance( indexGraph ) ) {
final CompositeFetch indexGraphAsCompositeFetch = (CompositeFetch) indexGraph;
printWriter.println( extractDetails( indexGraphAsCompositeFetch ) );
writeCompositeFetchFetches( indexGraphAsCompositeFetch, depth+1, printWriter );
}
}
final CollectionFetchableElement elementGraph = collectionReference.getElementGraph();
if ( elementGraph != null ) {
printWriter.print( TreePrinterHelper.INSTANCE.generateNodePrefix( depth ) + "(collection element) " );
if ( EntityReference.class.isInstance( elementGraph ) ) {
final EntityReference elementGraphAsEntityReference = (EntityReference) elementGraph;
printWriter.println( extractDetails( elementGraphAsEntityReference ) );
writeEntityReferenceFetches( elementGraphAsEntityReference, depth+1, printWriter );
}
else if ( CompositeFetch.class.isInstance( elementGraph ) ) {
final CompositeFetch elementGraphAsCompositeFetch = (CompositeFetch) elementGraph;
printWriter.println( extractDetails( elementGraphAsCompositeFetch ) );
writeCompositeFetchFetches( elementGraphAsCompositeFetch, depth+1, printWriter );
}
}
}
}