@ -24,7 +24,6 @@ import java.util.Set;
@@ -24,7 +24,6 @@ import java.util.Set;
import org.apache.commons.logging.Log ;
import org.apache.commons.logging.LogFactory ;
import org.jspecify.annotations.NonNull ;
import org.jspecify.annotations.Nullable ;
import org.springframework.data.mapping.Parameter ;
@ -32,6 +31,7 @@ import org.springframework.data.mapping.PreferredConstructor;
@@ -32,6 +31,7 @@ import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.mapping.model.PreferredConstructorDiscoverer ;
import org.springframework.data.projection.ProjectionFactory ;
import org.springframework.data.projection.ProjectionInformation ;
import org.springframework.data.util.Lazy ;
import org.springframework.lang.Contract ;
import org.springframework.util.Assert ;
import org.springframework.util.ClassUtils ;
@ -83,7 +83,7 @@ public abstract class ReturnedType {
@@ -83,7 +83,7 @@ public abstract class ReturnedType {
}
/ * *
* Returns the entity type .
* Return the entity type .
*
* @return
* /
@ -92,7 +92,7 @@ public abstract class ReturnedType {
@@ -92,7 +92,7 @@ public abstract class ReturnedType {
}
/ * *
* Returns whether the given source object is an instance of the returned type .
* Return whether the given source object is an instance of the returned type .
*
* @param source can be { @literal null } .
* @return
@ -103,46 +103,47 @@ public abstract class ReturnedType {
@@ -103,46 +103,47 @@ public abstract class ReturnedType {
}
/ * *
* Returns whether the type is projecting , i . e . not of the domain type .
* Return the type of the individual objects to return .
*
* @return
* /
public abstract boolean isProjecting ( ) ;
public abstract Class < ? > getReturnedType ( ) ;
/ * *
* Returns the type of the individual objects to return .
* Return whether the type is projecting , i . e . not of the domain type .
*
* @return
* /
public abstract Class < ? > getReturnedType ( ) ;
public abstract boolean isProjecting ( ) ;
/ * *
* Returns whether the returned type will require custom constru ction.
* Return whether the type is an interface - proje ction.
*
* @return
* @since 4 . 0 . 1
* /
public abstract boolean needsCustomConstruction ( ) ;
public boolean isInterfaceProjection ( ) {
return isProjecting ( ) & & getReturnedType ( ) . isInterface ( ) ;
}
/ * *
* Returns the type that the query execution is supposed to pass to the underlying infrastructure . { @literal null } is
* returned to indicate a generic type ( a map or tuple - like type ) shall be used .
* Return whether the type is a DTO projection .
*
* @return
* @since 4 . 0 . 1
* /
public abstract @Nullable Class < ? > getTypeToRead ( ) ;
public boolean isDtoProjection ( ) {
return isProjecting ( ) & & ! getReturnedType ( ) . isInterface ( ) ;
}
/ * *
* Returns the properties required to be used to populate the result .
* Return the properties required to be used to populate the result .
*
* @return
* @see ProjectionInformation # getInputProperties ( )
* /
public abstract List < String > getInputProperties ( ) ;
/ * *
* Returns whether the returned type has input properties .
* Return whether the returned type has input properties .
*
* @return
* @since 3 . 3 . 5
* @see ProjectionInformation # hasInputProperties ( )
* /
@ -150,16 +151,29 @@ public abstract class ReturnedType {
@@ -150,16 +151,29 @@ public abstract class ReturnedType {
return ! CollectionUtils . isEmpty ( getInputProperties ( ) ) ;
}
/ * *
* Return whether the returned type will require custom construction .
* /
public abstract boolean needsCustomConstruction ( ) ;
/ * *
* Return the type that the query execution is supposed to pass to the underlying infrastructure . { @literal null } is
* returned to indicate a generic type ( a map or tuple - like type ) shall be used .
* /
public abstract @Nullable Class < ? > getTypeToRead ( ) ;
/ * *
* A { @link ReturnedType } that ' s backed by an interface .
*
* @author Oliver Gierke
* @author Mark Paluch
* @since 1 . 12
* /
private static final class ReturnedInterface extends ReturnedType {
private final ProjectionInformation information ;
private final Class < ? > domainType ;
private final boolean isProjecting ;
private final List < String > inputProperties ;
/ * *
@ -176,6 +190,7 @@ public abstract class ReturnedType {
@@ -176,6 +190,7 @@ public abstract class ReturnedType {
this . information = information ;
this . domainType = domainType ;
this . isProjecting = ! information . getType ( ) . isAssignableFrom ( domainType ) ;
this . inputProperties = detectInputProperties ( information ) ;
}
@ -198,24 +213,35 @@ public abstract class ReturnedType {
@@ -198,24 +213,35 @@ public abstract class ReturnedType {
}
@Override
public boolean needsCustomConstruction ( ) {
return isProjecting ( ) & & information . isClosed ( ) ;
public boolean isProjecting ( ) {
return isProjecting ;
}
@Override
public boolean isProjecting ( ) {
return ! information . getType ( ) . isAssignableFrom ( domainType ) ;
public boolean isInterface Projectio n ( ) {
return isProjecting ( ) ;
}
@Override
public @Nullable Class < ? > getTypeToRead ( ) {
return isProjecting ( ) & & information . isClosed ( ) ? null : domainTyp e;
public boolean isDtoProjection ( ) {
return fals e;
}
@Override
public List < String > getInputProperties ( ) {
return inputProperties ;
}
@Override
public boolean needsCustomConstruction ( ) {
return isProjecting ( ) & & information . isClosed ( ) ;
}
@Override
public @Nullable Class < ? > getTypeToRead ( ) {
return isProjecting ( ) & & information . isClosed ( ) ? null : domainType ;
}
}
/ * *
@ -223,6 +249,7 @@ public abstract class ReturnedType {
@@ -223,6 +249,7 @@ public abstract class ReturnedType {
*
* @author Oliver Gierke
* @author Mikhail Polivakha
* @author Mark Paluch
* @since 1 . 12
* /
private static final class ReturnedClass extends ReturnedType {
@ -231,7 +258,8 @@ public abstract class ReturnedType {
@@ -231,7 +258,8 @@ public abstract class ReturnedType {
private final Class < ? > type ;
private final boolean isDto ;
private final List < String > inputProperties ;
private final @Nullable PreferredConstructor < ? , ? > constructor ;
private final Lazy < List < String > > inputProperties ;
/ * *
* Creates a new { @link ReturnedClass } instance for the given returned type and domain type .
@ -256,7 +284,13 @@ public abstract class ReturnedType {
@@ -256,7 +284,13 @@ public abstract class ReturnedType {
! VOID_TYPES . contains ( type ) & & //
! type . getPackage ( ) . getName ( ) . startsWith ( "java." ) ;
this . inputProperties = detectConstructorParameterNames ( returnedType ) ;
this . constructor = detectConstructor ( type ) ;
if ( this . constructor = = null ) {
this . inputProperties = Lazy . of ( Collections . emptyList ( ) ) ;
} else {
this . inputProperties = Lazy . of ( this : : detectConstructorParameterNames ) ;
}
}
@Override
@ -265,33 +299,53 @@ public abstract class ReturnedType {
@@ -265,33 +299,53 @@ public abstract class ReturnedType {
}
@Override
@NonNull
public Class < ? > getTypeToRead ( ) {
return type ;
public boolean isProjecting ( ) {
return isDto ;
}
@Override
public boolean isProjecting ( ) {
return isDto ( ) ;
public boolean isInterface Projectio n ( ) {
return false ;
}
@Override
public boolean needsCustomConstru ction( ) {
return isDto ( ) & & ! inputProperties . isEmpty ( ) ;
public boolean isDtoProje ction( ) {
return isProjecting ( ) ;
}
@Override
public List < String > getInputProperties ( ) {
return inputProperties ;
return inputProperties . get ( ) ;
}
private List < String > detectConstructorParameterNames ( Class < ? > type ) {
@Override
public boolean hasInputProperties ( ) {
return this . constructor ! = null & & this . constructor . getParameterCount ( ) > 0 & & super . hasInputProperties ( ) ;
}
if ( ! isDto ( ) ) {
return Collections . emptyList ( ) ;
}
@Override
public boolean needsCustomConstruction ( ) {
return isDtoProjection ( ) & & hasInputProperties ( ) ;
}
PreferredConstructor < ? , ? > constructor = PreferredConstructorDiscoverer . discover ( type ) ;
@Override
public Class < ? > getTypeToRead ( ) {
return type ;
}
private boolean isDomainSubtype ( ) {
return getDomainType ( ) . equals ( type ) & & getDomainType ( ) . isAssignableFrom ( type ) ;
}
private boolean isPrimitiveOrWrapper ( ) {
return ClassUtils . isPrimitiveOrWrapper ( type ) ;
}
private @Nullable PreferredConstructor < ? , ? > detectConstructor ( Class < ? > type ) {
return isDtoProjection ( ) ? PreferredConstructorDiscoverer . discover ( type ) : null ;
}
private List < String > detectConstructorParameterNames ( ) {
if ( constructor = = null ) {
return Collections . emptyList ( ) ;
@ -310,24 +364,13 @@ public abstract class ReturnedType {
@@ -310,24 +364,13 @@ public abstract class ReturnedType {
if ( logger . isWarnEnabled ( ) ) {
logger . warn ( ( "No constructor parameter names discovered. "
+ "Compile the affected code with '-parameters' instead or avoid its introspection: %s" )
. formatted ( type . getName ( ) ) ) ;
. formatted ( constructor . getConstructor ( ) . getDeclaringClass ( ) . getName ( ) ) ) ;
}
}
return Collections . unmodifiableList ( properties ) ;
}
private boolean isDto ( ) {
return isDto ;
}
private boolean isDomainSubtype ( ) {
return getDomainType ( ) . equals ( type ) & & getDomainType ( ) . isAssignableFrom ( type ) ;
}
private boolean isPrimitiveOrWrapper ( ) {
return ClassUtils . isPrimitiveOrWrapper ( type ) ;
}
}
private static final class CacheKey {
@ -396,5 +439,7 @@ public abstract class ReturnedType {
@@ -396,5 +439,7 @@ public abstract class ReturnedType {
return "ReturnedType.CacheKey(returnedType=" + this . getReturnedType ( ) + ", domainType=" + this . getDomainType ( )
+ ", projectionFactoryHashCode=" + this . getProjectionFactoryHashCode ( ) + ")" ;
}
}
}