HHH-16389 Introduce checkerframework for nullness marking/checking and null check the JPA metamodel generator
This commit is contained in:
parent
0da73a27a5
commit
484cbfe720
|
@ -25,6 +25,8 @@ plugins {
|
||||||
id 'org.hibernate.orm.database-service' apply false
|
id 'org.hibernate.orm.database-service' apply false
|
||||||
id 'biz.aQute.bnd' version '6.3.1' apply false
|
id 'biz.aQute.bnd' version '6.3.1' apply false
|
||||||
|
|
||||||
|
id 'org.checkerframework' version '0.6.25'
|
||||||
|
|
||||||
id 'io.github.gradle-nexus.publish-plugin' version '1.1.0'
|
id 'io.github.gradle-nexus.publish-plugin' version '1.1.0'
|
||||||
|
|
||||||
id 'idea'
|
id 'idea'
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
// Checkerframework stubs for the jakarta.persistence module
|
||||||
|
|
||||||
|
package jakarta.persistence;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
public interface AttributeConverter<X,Y> {
|
||||||
|
public @Nullable Y convertToDatabaseColumn(@Nullable X attribute);
|
||||||
|
public @Nullable X convertToEntityAttribute(@Nullable Y dbData);
|
||||||
|
}
|
||||||
|
public interface EntityManager extends AutoCloseable {
|
||||||
|
public <T> @Nullable T find(Class<T> entityClass, Object primaryKey);
|
||||||
|
public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties);
|
||||||
|
public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode);
|
||||||
|
public <T> @Nullable T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties);
|
||||||
|
}
|
||||||
|
public interface EntityManagerFactory extends AutoCloseable {
|
||||||
|
public @Nullable Cache getCache();
|
||||||
|
}
|
||||||
|
public interface Parameter {
|
||||||
|
public @Nullable String getName();
|
||||||
|
public @Nullable Integer getPosition();
|
||||||
|
}
|
||||||
|
public interface PersistenceUnitUtil extends PersistenceUtil {
|
||||||
|
public @Nullable Object getIdentifier(Object entity);
|
||||||
|
}
|
||||||
|
public interface Query {
|
||||||
|
<T> Query setParameter(Parameter<T> param, @Nullable T value);
|
||||||
|
Query setParameter(Parameter<Calendar> param, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
Query setParameter(Parameter<Date> param, @Nullable Date value, TemporalType temporalType);
|
||||||
|
Query setParameter(String name, @Nullable Object value);
|
||||||
|
Query setParameter(String name, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
Query setParameter(String name, @Nullable Date value, TemporalType temporalType);
|
||||||
|
Query setParameter(int position, @Nullable Object value);
|
||||||
|
Query setParameter(int position, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
Query setParameter(int position, @Nullable Date value, TemporalType temporalType);
|
||||||
|
<T> @Nullable T getParameterValue(Parameter<T> param);
|
||||||
|
@Nullable Object getParameterValue(String name);
|
||||||
|
@Nullable Object getParameterValue(int position);
|
||||||
|
}
|
||||||
|
public interface StoredProcedureQuery extends Query {
|
||||||
|
<T> StoredProcedureQuery setParameter(Parameter<T> param, @Nullable T value);
|
||||||
|
StoredProcedureQuery setParameter(Parameter<Calendar> param, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
StoredProcedureQuery setParameter(Parameter<Date> param, @Nullable Date value, TemporalType temporalType);
|
||||||
|
StoredProcedureQuery setParameter(String name, @Nullable Object value);
|
||||||
|
StoredProcedureQuery setParameter(String name, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
StoredProcedureQuery setParameter(String name, @Nullable Date value, TemporalType temporalType);
|
||||||
|
StoredProcedureQuery setParameter(int position, @Nullable Object value);
|
||||||
|
StoredProcedureQuery setParameter(int position, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
StoredProcedureQuery setParameter(int position, @Nullable Date value, TemporalType temporalType);
|
||||||
|
@Nullable Object getOutputParameterValue(int position);
|
||||||
|
@Nullable Object getOutputParameterValue(String parameterName);
|
||||||
|
}
|
||||||
|
public interface TypedQuery<X> extends Query {
|
||||||
|
<T> TypedQuery<X> setParameter(Parameter<T> param, @Nullable T value);
|
||||||
|
TypedQuery<X> setParameter(Parameter<Calendar> param, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
TypedQuery<X> setParameter(Parameter<Date> param, @Nullable Date value, TemporalType temporalType);
|
||||||
|
TypedQuery<X> setParameter(String name, @Nullable Object value);
|
||||||
|
TypedQuery<X> setParameter(String name, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
TypedQuery<X> setParameter(String name, @Nullable Date value, TemporalType temporalType);
|
||||||
|
TypedQuery<X> setParameter(int position, @Nullable Object value);
|
||||||
|
TypedQuery<X> setParameter(int position, @Nullable Calendar value, TemporalType temporalType);
|
||||||
|
TypedQuery<X> setParameter(int position, @Nullable Date value, TemporalType temporalType);
|
||||||
|
@Nullable Object getOutputParameterValue(int position);
|
||||||
|
@Nullable Object getOutputParameterValue(String parameterName);
|
||||||
|
}
|
||||||
|
public interface Tuple {
|
||||||
|
<X> @Nullable X get(TupleElement<X> tupleElement);
|
||||||
|
<X> @Nullable X get(String alias, Class<X> type);
|
||||||
|
@Nullable Object get(String alias);
|
||||||
|
<X> @Nullable X get(int i, Class<X> type);
|
||||||
|
@Nullable Object get(int i);
|
||||||
|
@Nullable Object[] toArray();
|
||||||
|
}
|
||||||
|
public interface TupleElement<X> {
|
||||||
|
@Nullable String getAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
package jakarta.persistence.criteria;
|
||||||
|
|
||||||
|
public interface CommonAbstractCriteria {
|
||||||
|
@Nullable Predicate getRestriction();
|
||||||
|
}
|
||||||
|
public interface AbstractQuery<T> extends CommonAbstractCriteria {
|
||||||
|
AbstractQuery<T> where(@Nullable Expression<Boolean> restriction);
|
||||||
|
AbstractQuery<T> where(@Nullable Predicate... restrictions);
|
||||||
|
AbstractQuery<T> having(@Nullable Expression<Boolean> restriction);
|
||||||
|
AbstractQuery<T> having(@Nullable Predicate... restrictions);
|
||||||
|
@Nullable Selection<T> getSelection();
|
||||||
|
@Nullable Predicate getGroupRestriction();
|
||||||
|
}
|
||||||
|
public interface CriteriaUpdate<T> extends CommonAbstractCriteria {
|
||||||
|
<Y, X extends Y> CriteriaUpdate<T> set(SingularAttribute<? super T, Y> attribute, @Nullable X value);
|
||||||
|
<Y, X extends Y> CriteriaUpdate<T> set(Path<Y> attribute, @Nullable X value);
|
||||||
|
CriteriaUpdate<T> set(String attributeName, @Nullable Object value);
|
||||||
|
}
|
||||||
|
public interface Subquery<T> extends AbstractQuery<T>, Expression<T> {
|
||||||
|
Subquery<T> where(@Nullable Expression<Boolean> restriction);
|
||||||
|
Subquery<T> where(@Nullable Predicate... restrictions);
|
||||||
|
Subquery<T> having(@Nullable Expression<Boolean> restriction);
|
||||||
|
Subquery<T> having(@Nullable Predicate... restrictions);
|
||||||
|
@Nullable Expression<T> getSelection();
|
||||||
|
}
|
||||||
|
public interface CriteriaBuilder {
|
||||||
|
public static interface SimpleCase<C,R> extends Expression<R> {
|
||||||
|
SimpleCase<C, R> when(C condition, @Nullable R result);
|
||||||
|
SimpleCase<C, R> when(Expression<? extends C> condition, @Nullable R result);
|
||||||
|
Expression<R> otherwise(@Nullable R result);
|
||||||
|
}
|
||||||
|
public static interface Case<R> extends Expression<R> {
|
||||||
|
Case<R> when(Expression<Boolean> condition, @Nullable R result);
|
||||||
|
Expression<R> otherwise(@Nullable R result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public interface Join<Z, X> extends From<Z, X> {
|
||||||
|
Join<Z, X> on(@Nullable Expression<Boolean> restriction);
|
||||||
|
Join<Z, X> on(@Nullable Predicate... restrictions);
|
||||||
|
@Nullable Predicate getOn();
|
||||||
|
}
|
||||||
|
public interface SetJoin<Z,E> extends PluralJoin<Z, Set<E>, E> {
|
||||||
|
SetJoin<Z, E> on(@Nullable Expression<Boolean> restriction);
|
||||||
|
SetJoin<Z, E> on(@Nullable Predicate... restrictions);
|
||||||
|
}
|
||||||
|
public interface ListJoin<Z,E> extends PluralJoin<Z, List<E>, E> {
|
||||||
|
ListJoin<Z, E> on(@Nullable Expression<Boolean> restriction);
|
||||||
|
ListJoin<Z, E> on(@Nullable Predicate... restrictions);
|
||||||
|
}
|
||||||
|
public interface MapJoin<Z,K,V> extends PluralJoin<Z, Map<K,V>, V> {
|
||||||
|
MapJoin<Z,K,V> on(@Nullable Expression<Boolean> restriction);
|
||||||
|
MapJoin<Z,K,V> on(@Nullable Predicate... restrictions);
|
||||||
|
}
|
||||||
|
public interface Path<X> extends Expression<X> {
|
||||||
|
// CteRoot etc.
|
||||||
|
@Nullable Bindable<X> getModel();
|
||||||
|
@Nullable Path<?> getParentPath();
|
||||||
|
MapJoin<Z,K,V> on(@Nullable Predicate... restrictions);
|
||||||
|
}
|
||||||
|
|
||||||
|
package jakarta.persistence.metamodel;
|
||||||
|
|
||||||
|
public interface IdentifiableType<X> extends ManagedType<X> {
|
||||||
|
@Nullable IdentifiableType<? super X> getSupertype();
|
||||||
|
}
|
||||||
|
|
||||||
|
package jakarta.persistence.spi;
|
||||||
|
|
||||||
|
public interface ClassTransformer {
|
||||||
|
@Nullable byte[] transform(
|
||||||
|
@Nullable ClassLoader loader,
|
||||||
|
String className,
|
||||||
|
@Nullable Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain,
|
||||||
|
byte[] classfileBuffer) throws TransformerException;
|
||||||
|
}
|
||||||
|
public interface PersistenceProvider {
|
||||||
|
public @Nullable EntityManagerFactory createEntityManagerFactory(String emName, @Nullable Map map);
|
||||||
|
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, @Nullable Map map);
|
||||||
|
}
|
||||||
|
public interface PersistenceUnitInfo {
|
||||||
|
public @Nullable String getPersistenceProviderClassName();
|
||||||
|
public @Nullable PersistenceUnitTransactionType getTransactionType();
|
||||||
|
public @Nullable DataSource getJtaDataSource();
|
||||||
|
public @Nullable DataSource getNonJtaDataSource();
|
||||||
|
public @Nullable ClassLoader getClassLoader();
|
||||||
|
public @Nullable ClassLoader getNewTempClassLoader();
|
||||||
|
}
|
|
@ -31,6 +31,8 @@ apply plugin: 'java-library'
|
||||||
apply plugin: 'biz.aQute.bnd.builder'
|
apply plugin: 'biz.aQute.bnd.builder'
|
||||||
apply plugin: 'org.hibernate.orm.database-service'
|
apply plugin: 'org.hibernate.orm.database-service'
|
||||||
|
|
||||||
|
apply plugin: 'org.checkerframework'
|
||||||
|
|
||||||
apply plugin: 'checkstyle'
|
apply plugin: 'checkstyle'
|
||||||
apply plugin: 'build-dashboard'
|
apply plugin: 'build-dashboard'
|
||||||
apply plugin: 'project-report'
|
apply plugin: 'project-report'
|
||||||
|
@ -502,6 +504,9 @@ checkstyle {
|
||||||
|
|
||||||
// exclude generated java sources - by explicitly setting the base source dir
|
// exclude generated java sources - by explicitly setting the base source dir
|
||||||
tasks.checkstyleMain.source = 'src/main/java'
|
tasks.checkstyleMain.source = 'src/main/java'
|
||||||
|
tasks.checkstyleMain
|
||||||
|
.exclude('org/hibernate/jpamodelgen/util/NullnessUtil.java')
|
||||||
|
.exclude('org/hibernate/internal/util/NullnessUtil.java')
|
||||||
|
|
||||||
// define a second checkstyle task for checking non-fatal violations
|
// define a second checkstyle task for checking non-fatal violations
|
||||||
task nonFatalCheckstyle(type:Checkstyle) {
|
task nonFatalCheckstyle(type:Checkstyle) {
|
||||||
|
@ -511,6 +516,17 @@ task nonFatalCheckstyle(type:Checkstyle) {
|
||||||
configFile = rootProject.file( 'shared/config/checkstyle/checkstyle-non-fatal.xml' )
|
configFile = rootProject.file( 'shared/config/checkstyle/checkstyle-non-fatal.xml' )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkerFramework {
|
||||||
|
checkers = [
|
||||||
|
'org.checkerframework.checker.nullness.NullnessChecker'
|
||||||
|
]
|
||||||
|
extraJavacArgs = [
|
||||||
|
'-AsuppressWarnings=initialization',
|
||||||
|
"-Astubs=${project.rootDir}/checkerstubs",
|
||||||
|
'-AonlyDefs=^org\\.hibernate\\.jpamodelgen\\.'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
task forbiddenApisSystemOut(type: CheckForbiddenApis, dependsOn: compileJava) {
|
task forbiddenApisSystemOut(type: CheckForbiddenApis, dependsOn: compileJava) {
|
||||||
bundledSignatures += 'jdk-system-out'
|
bundledSignatures += 'jdk-system-out'
|
||||||
|
|
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* Checker Framework utilities
|
||||||
|
* Copyright 2004-present by the Checker Framework developers
|
||||||
|
*
|
||||||
|
* MIT License:
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package org.hibernate.internal.util;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.checkerframework.framework.qual.AnnotatedFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for the Nullness Checker.
|
||||||
|
*
|
||||||
|
* <p>To avoid the need to write the NullnessUtil class name, do:
|
||||||
|
*
|
||||||
|
* <pre>import static org.checkerframework.checker.nullness.util.NullnessUtil.castNonNull;</pre>
|
||||||
|
* <p>
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* <pre>import static org.checkerframework.checker.nullness.util.NullnessUtil.*;</pre>
|
||||||
|
*
|
||||||
|
* <p><b>Runtime Dependency</b>: If you use this class, you must distribute (or link to) {@code
|
||||||
|
* checker-qual.jar}, along with your binaries. Or, you can copy this class into your own project.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({
|
||||||
|
"nullness", // Nullness utilities are trusted regarding nullness.
|
||||||
|
"cast" // Casts look redundant if Nullness Checker is not run.
|
||||||
|
})
|
||||||
|
@AnnotatedFor("nullness")
|
||||||
|
public final class NullnessUtil {
|
||||||
|
|
||||||
|
private NullnessUtil() {
|
||||||
|
throw new AssertionError( "shouldn't be instantiated" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that suppresses warnings from the Nullness Checker.
|
||||||
|
*
|
||||||
|
* <p>The method takes a possibly-null reference, unsafely casts it to have the @NonNull type
|
||||||
|
* qualifier, and returns it. The Nullness Checker considers both the return value, and also the
|
||||||
|
* argument, to be non-null after the method call. Therefore, the {@code castNonNull} method can
|
||||||
|
* be used either as a cast expression or as a statement. The Nullness Checker issues no warnings
|
||||||
|
* in any of the following code:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* // one way to use as a cast:
|
||||||
|
* {@literal @}NonNull String s = castNonNull(possiblyNull1);
|
||||||
|
*
|
||||||
|
* // another way to use as a cast:
|
||||||
|
* castNonNull(possiblyNull2).toString();
|
||||||
|
*
|
||||||
|
* // one way to use as a statement:
|
||||||
|
* castNonNull(possiblyNull3);
|
||||||
|
* possiblyNull3.toString();`
|
||||||
|
* </code></pre>
|
||||||
|
* <p>
|
||||||
|
* The {@code castNonNull} method is intended to be used in situations where the programmer
|
||||||
|
* definitively knows that a given reference is not null, but the type system is unable to make
|
||||||
|
* this deduction. It is not intended for defensive programming, in which a programmer cannot
|
||||||
|
* prove that the value is not null but wishes to have an earlier indication if it is. See the
|
||||||
|
* Checker Framework Manual for further discussion.
|
||||||
|
*
|
||||||
|
* <p>The method throws {@link AssertionError} if Java assertions are enabled and the argument is
|
||||||
|
* {@code null}. If the exception is ever thrown, then that indicates that the programmer misused
|
||||||
|
* the method by using it in a circumstance where its argument can be null.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the reference
|
||||||
|
* @param ref a reference of @Nullable type, that is non-null at run time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T castNonNull(@Nullable T ref) {
|
||||||
|
assert ref != null : "Misuse of castNonNull: called with a null argument";
|
||||||
|
return (@NonNull T) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suppress warnings from the Nullness Checker, with a custom error message. See {@link
|
||||||
|
* #castNonNull(Object)} for documentation.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the reference
|
||||||
|
* @param ref a reference of @Nullable type, that is non-null at run time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
public static @EnsuresNonNull("#1") <T extends @Nullable Object> @NonNull T castNonNull(
|
||||||
|
@Nullable T ref, String message) {
|
||||||
|
assert ref != null : "Misuse of castNonNull: called with a null argument: " + message;
|
||||||
|
return (@NonNull T) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullDeep(
|
||||||
|
T @Nullable [] arr) {
|
||||||
|
return (@NonNull T[]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullDeep(
|
||||||
|
T @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (three levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (three levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (four levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (four levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (five levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of castNonNullDeep.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (five levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if there is a non-null value, or null to use uncustomized
|
||||||
|
* message
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*/
|
||||||
|
private static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullArray(
|
||||||
|
T @Nullable [] arr, @Nullable String message) {
|
||||||
|
assert arr != null
|
||||||
|
: "Misuse of castNonNullArray: called with a null array argument"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
for ( int i = 0; i < arr.length; ++i ) {
|
||||||
|
assert arr[i] != null
|
||||||
|
: "Misuse of castNonNull: called with a null array element"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
checkIfArray( arr[i], message );
|
||||||
|
}
|
||||||
|
return (@NonNull T[]) arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the argument is an array, requires it to be non-null at all levels.
|
||||||
|
*
|
||||||
|
* @param ref a value; if an array, all of its elements, and their elements recursively, are
|
||||||
|
* non-null at run time
|
||||||
|
* @param message text to include if there is a non-null value, or null to use uncustomized
|
||||||
|
* message
|
||||||
|
*/
|
||||||
|
private static void checkIfArray(@NonNull Object ref, @Nullable String message) {
|
||||||
|
assert ref != null
|
||||||
|
: "Misuse of checkIfArray: called with a null argument"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
Class<?> comp = ref.getClass().getComponentType();
|
||||||
|
if ( comp != null ) {
|
||||||
|
// comp is non-null for arrays, otherwise null.
|
||||||
|
if ( comp.isPrimitive() ) {
|
||||||
|
// Nothing to do for arrays of primitive type: primitives are
|
||||||
|
// never null.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
castNonNullArray( (Object[]) ref, message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,8 @@ import org.hibernate.jpamodelgen.model.MetaEntity;
|
||||||
import org.hibernate.jpamodelgen.util.Constants;
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to write the actual meta model class using the {@link javax.annotation.processing.Filer} API.
|
* Helper class to write the actual meta model class using the {@link javax.annotation.processing.Filer} API.
|
||||||
*
|
*
|
||||||
|
@ -35,6 +37,8 @@ import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
*/
|
*/
|
||||||
public final class ClassWriter {
|
public final class ClassWriter {
|
||||||
private static final String META_MODEL_CLASS_NAME_SUFFIX = "_";
|
private static final String META_MODEL_CLASS_NAME_SUFFIX = "_";
|
||||||
|
// See https://github.com/typetools/checker-framework/issues/979
|
||||||
|
@SuppressWarnings( "type.argument" )
|
||||||
private static final ThreadLocal<SimpleDateFormat> SIMPLE_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
|
private static final ThreadLocal<SimpleDateFormat> SIMPLE_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
|
||||||
@Override
|
@Override
|
||||||
public SimpleDateFormat initialValue() {
|
public SimpleDateFormat initialValue() {
|
||||||
|
@ -140,7 +144,7 @@ public final class ClassWriter {
|
||||||
pw.println( " {" );
|
pw.println( " {" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String findMappedSuperClass(MetaEntity entity, Context context) {
|
private static @Nullable String findMappedSuperClass(MetaEntity entity, Context context) {
|
||||||
TypeMirror superClass = entity.getTypeElement().getSuperclass();
|
TypeMirror superClass = entity.getTypeElement().getSuperclass();
|
||||||
//superclass of Object is of NoType which returns some other kind
|
//superclass of Object is of NoType which returns some other kind
|
||||||
while ( superClass.getKind() == TypeKind.DECLARED ) {
|
while ( superClass.getKind() == TypeKind.DECLARED ) {
|
||||||
|
|
|
@ -24,6 +24,8 @@ import org.hibernate.jpamodelgen.util.AccessType;
|
||||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||||
import org.hibernate.jpamodelgen.util.Constants;
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Max Andersen
|
* @author Max Andersen
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
|
@ -68,21 +70,21 @@ public final class Context {
|
||||||
public Context(ProcessingEnvironment pe) {
|
public Context(ProcessingEnvironment pe) {
|
||||||
this.pe = pe;
|
this.pe = pe;
|
||||||
|
|
||||||
if ( pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION ) != null ) {
|
String persistenceXmlOption = pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION );
|
||||||
String tmp = pe.getOptions().get( JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION );
|
if ( persistenceXmlOption != null ) {
|
||||||
if ( !tmp.startsWith( Constants.PATH_SEPARATOR ) ) {
|
if ( !persistenceXmlOption.startsWith( Constants.PATH_SEPARATOR ) ) {
|
||||||
tmp = Constants.PATH_SEPARATOR + tmp;
|
persistenceXmlOption = Constants.PATH_SEPARATOR + persistenceXmlOption;
|
||||||
}
|
}
|
||||||
persistenceXmlLocation = tmp;
|
persistenceXmlLocation = persistenceXmlOption;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
persistenceXmlLocation = DEFAULT_PERSISTENCE_XML_LOCATION;
|
persistenceXmlLocation = DEFAULT_PERSISTENCE_XML_LOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION ) != null ) {
|
String ormXmlOption = pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION );
|
||||||
String tmp = pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION );
|
if ( ormXmlOption != null ) {
|
||||||
ormXmlFiles = new ArrayList<String>();
|
ormXmlFiles = new ArrayList<>();
|
||||||
for ( String ormFile : tmp.split( "," ) ) {
|
for ( String ormFile : ormXmlOption.split( "," ) ) {
|
||||||
if ( !ormFile.startsWith( Constants.PATH_SEPARATOR ) ) {
|
if ( !ormFile.startsWith( Constants.PATH_SEPARATOR ) ) {
|
||||||
ormFile = Constants.PATH_SEPARATOR + ormFile;
|
ormFile = Constants.PATH_SEPARATOR + ormFile;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +163,7 @@ public final class Context {
|
||||||
return metaEntities.containsKey( fqcn );
|
return metaEntities.containsKey( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetaEntity getMetaEntity(String fqcn) {
|
public @Nullable MetaEntity getMetaEntity(String fqcn) {
|
||||||
return metaEntities.get( fqcn );
|
return metaEntities.get( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +179,7 @@ public final class Context {
|
||||||
return metaEmbeddables.containsKey( fqcn );
|
return metaEmbeddables.containsKey( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetaEntity getMetaEmbeddable(String fqcn) {
|
public @Nullable MetaEntity getMetaEmbeddable(String fqcn) {
|
||||||
return metaEmbeddables.get( fqcn );
|
return metaEmbeddables.get( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +195,7 @@ public final class Context {
|
||||||
accessTypeInformation.put( fqcn, info );
|
accessTypeInformation.put( fqcn, info );
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTypeInformation getAccessTypeInfo(String fqcn) {
|
public @Nullable AccessTypeInformation getAccessTypeInfo(String fqcn) {
|
||||||
return accessTypeInformation.get( fqcn );
|
return accessTypeInformation.get( fqcn );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ import org.hibernate.jpamodelgen.util.StringUtil;
|
||||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
|
import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main annotation processor.
|
* Main annotation processor.
|
||||||
*
|
*
|
||||||
|
@ -240,7 +242,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
||||||
requiresLazyMemberInitialization = true;
|
requiresLazyMemberInitialization = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
metaEntity = new AnnotationMetaEntity( (TypeElement) element, context, requiresLazyMemberInitialization );
|
metaEntity = AnnotationMetaEntity.create( (TypeElement) element, context, requiresLazyMemberInitialization );
|
||||||
|
|
||||||
if ( alreadyExistingMetaEntity != null ) {
|
if ( alreadyExistingMetaEntity != null ) {
|
||||||
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
|
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
|
||||||
|
@ -249,7 +251,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MetaEntity tryGettingExistingEntityFromContext(AnnotationMirror mirror, String fqn) {
|
private @Nullable MetaEntity tryGettingExistingEntityFromContext(AnnotationMirror mirror, String fqn) {
|
||||||
MetaEntity alreadyExistingMetaEntity = null;
|
MetaEntity alreadyExistingMetaEntity = null;
|
||||||
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ENTITY )
|
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ENTITY )
|
||||||
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS )) {
|
|| TypeUtils.isAnnotationMirrorOfType( mirror, Constants.MAPPED_SUPERCLASS )) {
|
||||||
|
|
|
@ -6,20 +6,24 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.jpamodelgen;
|
package org.hibernate.jpamodelgen;
|
||||||
|
|
||||||
|
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the Meta Model Generator version.
|
* Information about the Meta Model Generator version.
|
||||||
*
|
*
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
public final class Version {
|
public final class Version {
|
||||||
private static String version;
|
private static @Nullable String version;
|
||||||
|
|
||||||
private Version() {
|
private Version() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getVersionString() {
|
public static String getVersionString() {
|
||||||
if ( version == null ) {
|
if ( version == null ) {
|
||||||
version = Version.class.getPackage().getImplementationVersion();
|
version = NullnessUtil.castNonNull( Version.class.getPackage() ).getImplementationVersion();
|
||||||
if ( version == null ) {
|
if ( version == null ) {
|
||||||
version = "[WORKING]";
|
version = "[WORKING]";
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.hibernate.jpamodelgen.model.MetaEntity;
|
||||||
import org.hibernate.jpamodelgen.util.AccessType;
|
import org.hibernate.jpamodelgen.util.AccessType;
|
||||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||||
import org.hibernate.jpamodelgen.util.Constants;
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
|
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,14 +67,19 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
*/
|
*/
|
||||||
private MetaEntity entityToMerge;
|
private MetaEntity entityToMerge;
|
||||||
|
|
||||||
public AnnotationMetaEntity(TypeElement element, Context context, boolean lazilyInitialised) {
|
public AnnotationMetaEntity(TypeElement element, Context context) {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.members = new HashMap<String, MetaAttribute>();
|
this.members = new HashMap<>();
|
||||||
this.importContext = new ImportContextImpl( getPackageName() );
|
this.importContext = new ImportContextImpl( getPackageName( context, element ) );
|
||||||
if ( !lazilyInitialised ) {
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised) {
|
||||||
|
final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context );
|
||||||
|
if ( !lazilyInitialised ) {
|
||||||
|
annotationMetaEntity.init();
|
||||||
|
}
|
||||||
|
return annotationMetaEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTypeInformation getEntityAccessTypeInfo() {
|
public AccessTypeInformation getEntityAccessTypeInfo() {
|
||||||
|
@ -93,6 +99,10 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final String getPackageName() {
|
public final String getPackageName() {
|
||||||
|
return getPackageName( context, element );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPackageName(Context context, TypeElement element) {
|
||||||
PackageElement packageOf = context.getElementUtils().getPackageOf( element );
|
PackageElement packageOf = context.getElementUtils().getPackageOf( element );
|
||||||
return context.getElementUtils().getName( packageOf.getQualifiedName() ).toString();
|
return context.getElementUtils().getName( packageOf.getQualifiedName() ).toString();
|
||||||
}
|
}
|
||||||
|
@ -167,7 +177,8 @@ public class AnnotationMetaEntity implements MetaEntity {
|
||||||
getContext().logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
getContext().logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
||||||
|
|
||||||
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
TypeUtils.determineAccessTypeForHierarchy( element, context );
|
||||||
entityAccessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
||||||
|
entityAccessTypeInfo = NullnessUtil.castNonNull(accessTypeInfo);
|
||||||
|
|
||||||
List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
|
List<? extends Element> fieldsOfClass = ElementFilter.fieldsIn( element.getEnclosedElements() );
|
||||||
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
|
||||||
|
|
|
@ -25,13 +25,16 @@ import org.hibernate.jpamodelgen.Context;
|
||||||
import org.hibernate.jpamodelgen.util.AccessType;
|
import org.hibernate.jpamodelgen.util.AccessType;
|
||||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||||
import org.hibernate.jpamodelgen.util.Constants;
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
|
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||||
import org.hibernate.jpamodelgen.util.StringUtil;
|
import org.hibernate.jpamodelgen.util.StringUtil;
|
||||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<AnnotationMetaAttribute, Element> {
|
public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<@Nullable AnnotationMetaAttribute, Element> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FQCN of the Hibernate-specific {@code @Target} annotation.
|
* FQCN of the Hibernate-specific {@code @Target} annotation.
|
||||||
|
@ -54,12 +57,12 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) {
|
public @Nullable AnnotationMetaAttribute visitPrimitive(PrimitiveType t, Element element) {
|
||||||
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
return new AnnotationMetaSingleAttribute( entity, element, TypeUtils.toTypeString( t ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationMetaAttribute visitArray(ArrayType t, Element element) {
|
public @Nullable AnnotationMetaAttribute visitArray(ArrayType t, Element element) {
|
||||||
// METAGEN-2 - For now we handle arrays as SingularAttribute
|
// METAGEN-2 - For now we handle arrays as SingularAttribute
|
||||||
// The code below is an attempt to be closer to the spec and only allow byte[], Byte[], char[] and Character[]
|
// The code below is an attempt to be closer to the spec and only allow byte[], Byte[], char[] and Character[]
|
||||||
// AnnotationMetaSingleAttribute attribute = null;
|
// AnnotationMetaSingleAttribute attribute = null;
|
||||||
|
@ -81,7 +84,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) {
|
public @Nullable AnnotationMetaAttribute visitTypeVariable(TypeVariable t, Element element) {
|
||||||
// METAGEN-29 - for a type variable we use the upper bound
|
// METAGEN-29 - for a type variable we use the upper bound
|
||||||
TypeMirror mirror = t.getUpperBound();
|
TypeMirror mirror = t.getUpperBound();
|
||||||
TypeMirror erasedType = context.getTypeUtils().erasure( mirror );
|
TypeMirror erasedType = context.getTypeUtils().erasure( mirror );
|
||||||
|
@ -91,7 +94,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) {
|
public @Nullable AnnotationMetaAttribute visitDeclared(DeclaredType declaredType, Element element) {
|
||||||
AnnotationMetaAttribute metaAttribute = null;
|
AnnotationMetaAttribute metaAttribute = null;
|
||||||
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
||||||
// WARNING: .toString() is necessary here since Name equals does not compare to String
|
// WARNING: .toString() is necessary here since Name equals does not compare to String
|
||||||
|
@ -110,7 +113,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
return metaAttribute;
|
return metaAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnnotationMetaAttribute createMetaCollectionAttribute(DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection, String targetEntity) {
|
private @Nullable AnnotationMetaAttribute createMetaCollectionAttribute(DeclaredType declaredType, Element element, String fqNameOfReturnType, String collection, @Nullable String targetEntity) {
|
||||||
if ( TypeUtils.containsAnnotation( element, Constants.ELEMENT_COLLECTION ) ) {
|
if ( TypeUtils.containsAnnotation( element, Constants.ELEMENT_COLLECTION ) ) {
|
||||||
String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() );
|
String explicitTargetEntity = getTargetEntity( element.getAnnotationMirrors() );
|
||||||
TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
|
TypeMirror collectionElementType = TypeUtils.getCollectionElementType(
|
||||||
|
@ -164,7 +167,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) {
|
public @Nullable AnnotationMetaAttribute visitExecutable(ExecutableType t, Element p) {
|
||||||
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -196,13 +199,12 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
return returnedElement.asType().accept( basicVisitor, returnedElement );
|
return returnedElement.asType().accept( basicVisitor, returnedElement );
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnnotationMetaAttribute createAnnotationMetaAttributeForMap(DeclaredType declaredType, Element element, String collection, String targetEntity) {
|
private @Nullable AnnotationMetaAttribute createAnnotationMetaAttributeForMap(DeclaredType declaredType, Element element, String collection, @Nullable String targetEntity) {
|
||||||
|
final AnnotationMirror annotationMirror = TypeUtils.getAnnotationMirror( element, Constants.MAP_KEY_CLASS );
|
||||||
String keyType;
|
String keyType;
|
||||||
if ( TypeUtils.containsAnnotation( element, Constants.MAP_KEY_CLASS ) ) {
|
if ( annotationMirror != null ) {
|
||||||
TypeMirror typeMirror = (TypeMirror) TypeUtils.getAnnotationValue(
|
TypeMirror typeMirror = (TypeMirror) NullnessUtil.castNonNull(
|
||||||
TypeUtils.getAnnotationMirror(
|
TypeUtils.getAnnotationValue( annotationMirror, TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME )
|
||||||
element, Constants.MAP_KEY_CLASS
|
|
||||||
), TypeUtils.DEFAULT_ANNOTATION_PARAMETER_NAME
|
|
||||||
);
|
);
|
||||||
keyType = typeMirror.toString();
|
keyType = typeMirror.toString();
|
||||||
}
|
}
|
||||||
|
@ -218,7 +220,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getElementType(DeclaredType declaredType, String targetEntity) {
|
private String getElementType(DeclaredType declaredType, @Nullable String targetEntity) {
|
||||||
if ( targetEntity != null ) {
|
if ( targetEntity != null ) {
|
||||||
return targetEntity;
|
return targetEntity;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +249,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
*
|
*
|
||||||
* @return target entity class name as string or {@code null} if no targetEntity is here or if equals to void
|
* @return target entity class name as string or {@code null} if no targetEntity is here or if equals to void
|
||||||
*/
|
*/
|
||||||
private String getTargetEntity(List<? extends AnnotationMirror> annotations) {
|
private @Nullable String getTargetEntity(List<? extends AnnotationMirror> annotations) {
|
||||||
String fullyQualifiedTargetEntityName = null;
|
String fullyQualifiedTargetEntityName = null;
|
||||||
for ( AnnotationMirror mirror : annotations ) {
|
for ( AnnotationMirror mirror : annotations ) {
|
||||||
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ELEMENT_COLLECTION ) ) {
|
if ( TypeUtils.isAnnotationMirrorOfType( mirror, Constants.ELEMENT_COLLECTION ) ) {
|
||||||
|
@ -266,7 +268,7 @@ public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<Annotatio
|
||||||
return fullyQualifiedTargetEntityName;
|
return fullyQualifiedTargetEntityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFullyQualifiedClassNameOfTargetEntity(AnnotationMirror mirror, String parameterName) {
|
private @Nullable String getFullyQualifiedClassNameOfTargetEntity(AnnotationMirror mirror, String parameterName) {
|
||||||
assert mirror != null;
|
assert mirror != null;
|
||||||
assert parameterName != null;
|
assert parameterName != null;
|
||||||
|
|
||||||
|
@ -291,6 +293,7 @@ class BasicAttributeVisitor extends SimpleTypeVisitor6<Boolean, Element> {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
public BasicAttributeVisitor(Context context) {
|
public BasicAttributeVisitor(Context context) {
|
||||||
|
super( Boolean.FALSE );
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.jpamodelgen.util;
|
package org.hibernate.jpamodelgen.util;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates the access type information for a single class.
|
* Encapsulates the access type information for a single class.
|
||||||
*
|
*
|
||||||
|
@ -17,17 +19,17 @@ public class AccessTypeInformation {
|
||||||
/**
|
/**
|
||||||
* Access type explicitly specified in xml or on an entity.
|
* Access type explicitly specified in xml or on an entity.
|
||||||
*/
|
*/
|
||||||
private AccessType explicitAccessType;
|
private @Nullable AccessType explicitAccessType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default type for en entity. This type might change during the parsing/discovering process. The reason
|
* The default type for en entity. This type might change during the parsing/discovering process. The reason
|
||||||
* for that is the ability to mix and match xml and annotation configuration.
|
* for that is the ability to mix and match xml and annotation configuration.
|
||||||
*/
|
*/
|
||||||
private AccessType defaultAccessType;
|
private @Nullable AccessType defaultAccessType;
|
||||||
|
|
||||||
private static final AccessType DEFAULT_ACCESS_TYPE = AccessType.PROPERTY;
|
private static final AccessType DEFAULT_ACCESS_TYPE = AccessType.PROPERTY;
|
||||||
|
|
||||||
public AccessTypeInformation(String fqcn, AccessType explicitAccessType, AccessType defaultAccessType) {
|
public AccessTypeInformation(String fqcn, @Nullable AccessType explicitAccessType, @Nullable AccessType defaultAccessType) {
|
||||||
this.fqcn = fqcn;
|
this.fqcn = fqcn;
|
||||||
this.explicitAccessType = explicitAccessType;
|
this.explicitAccessType = explicitAccessType;
|
||||||
this.defaultAccessType = defaultAccessType;
|
this.defaultAccessType = defaultAccessType;
|
||||||
|
@ -58,7 +60,7 @@ public class AccessTypeInformation {
|
||||||
this.explicitAccessType = explicitAccessType;
|
this.explicitAccessType = explicitAccessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessType getDefaultAccessType() {
|
public @Nullable AccessType getDefaultAccessType() {
|
||||||
return defaultAccessType;
|
return defaultAccessType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hardy Ferentschik
|
* @author Hardy Ferentschik
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +28,7 @@ public class FileTimeStampChecker implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(@Nullable Object o) {
|
||||||
if ( this == o ) {
|
if ( this == o ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* Checker Framework utilities
|
||||||
|
* Copyright 2004-present by the Checker Framework developers
|
||||||
|
*
|
||||||
|
* MIT License:
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpamodelgen.util;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.checkerframework.framework.qual.AnnotatedFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for the Nullness Checker.
|
||||||
|
*
|
||||||
|
* <p>To avoid the need to write the NullnessUtil class name, do:
|
||||||
|
*
|
||||||
|
* <pre>import static org.checkerframework.checker.nullness.util.NullnessUtil.castNonNull;</pre>
|
||||||
|
* <p>
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* <pre>import static org.checkerframework.checker.nullness.util.NullnessUtil.*;</pre>
|
||||||
|
*
|
||||||
|
* <p><b>Runtime Dependency</b>: If you use this class, you must distribute (or link to) {@code
|
||||||
|
* checker-qual.jar}, along with your binaries. Or, you can copy this class into your own project.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({
|
||||||
|
"nullness", // Nullness utilities are trusted regarding nullness.
|
||||||
|
"cast" // Casts look redundant if Nullness Checker is not run.
|
||||||
|
})
|
||||||
|
@AnnotatedFor("nullness")
|
||||||
|
public final class NullnessUtil {
|
||||||
|
|
||||||
|
private NullnessUtil() {
|
||||||
|
throw new AssertionError( "shouldn't be instantiated" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that suppresses warnings from the Nullness Checker.
|
||||||
|
*
|
||||||
|
* <p>The method takes a possibly-null reference, unsafely casts it to have the @NonNull type
|
||||||
|
* qualifier, and returns it. The Nullness Checker considers both the return value, and also the
|
||||||
|
* argument, to be non-null after the method call. Therefore, the {@code castNonNull} method can
|
||||||
|
* be used either as a cast expression or as a statement. The Nullness Checker issues no warnings
|
||||||
|
* in any of the following code:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* // one way to use as a cast:
|
||||||
|
* {@literal @}NonNull String s = castNonNull(possiblyNull1);
|
||||||
|
*
|
||||||
|
* // another way to use as a cast:
|
||||||
|
* castNonNull(possiblyNull2).toString();
|
||||||
|
*
|
||||||
|
* // one way to use as a statement:
|
||||||
|
* castNonNull(possiblyNull3);
|
||||||
|
* possiblyNull3.toString();`
|
||||||
|
* </code></pre>
|
||||||
|
* <p>
|
||||||
|
* The {@code castNonNull} method is intended to be used in situations where the programmer
|
||||||
|
* definitively knows that a given reference is not null, but the type system is unable to make
|
||||||
|
* this deduction. It is not intended for defensive programming, in which a programmer cannot
|
||||||
|
* prove that the value is not null but wishes to have an earlier indication if it is. See the
|
||||||
|
* Checker Framework Manual for further discussion.
|
||||||
|
*
|
||||||
|
* <p>The method throws {@link AssertionError} if Java assertions are enabled and the argument is
|
||||||
|
* {@code null}. If the exception is ever thrown, then that indicates that the programmer misused
|
||||||
|
* the method by using it in a circumstance where its argument can be null.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the reference
|
||||||
|
* @param ref a reference of @Nullable type, that is non-null at run time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T castNonNull(@Nullable T ref) {
|
||||||
|
assert ref != null : "Misuse of castNonNull: called with a null argument";
|
||||||
|
return (@NonNull T) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suppress warnings from the Nullness Checker, with a custom error message. See {@link
|
||||||
|
* #castNonNull(Object)} for documentation.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the reference
|
||||||
|
* @param ref a reference of @Nullable type, that is non-null at run time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
public static @EnsuresNonNull("#1") <T extends @Nullable Object> @NonNull T castNonNull(
|
||||||
|
@Nullable T ref, String message) {
|
||||||
|
assert ref != null : "Misuse of castNonNull: called with a null argument: " + message;
|
||||||
|
return (@NonNull T) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullDeep(
|
||||||
|
T @Nullable [] arr) {
|
||||||
|
return (@NonNull T[]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullDeep(
|
||||||
|
T @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (three levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (three levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (four levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (four levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr) {
|
||||||
|
return (@NonNull T[][][][][]) castNonNullArray( arr, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like castNonNull, but whereas that method only checks and casts the reference itself, this
|
||||||
|
* traverses all levels of the argument array. The array is recursively checked to ensure that all
|
||||||
|
* elements at every array level are non-null.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (five levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if this method is misused
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*
|
||||||
|
* @see #castNonNull(Object)
|
||||||
|
*/
|
||||||
|
@EnsuresNonNull("#1")
|
||||||
|
public static <T extends @Nullable Object> @NonNull T @NonNull [][][][][] castNonNullDeep(
|
||||||
|
T @Nullable [] @Nullable [] @Nullable [] @Nullable [] @Nullable [] arr, String message) {
|
||||||
|
return (@NonNull T[][][][][]) castNonNullArray( arr, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of castNonNullDeep.
|
||||||
|
*
|
||||||
|
* @param <T> the component type (five levels in) of the array
|
||||||
|
* @param arr an array all of whose elements, and their elements recursively, are non-null at run
|
||||||
|
* time
|
||||||
|
* @param message text to include if there is a non-null value, or null to use uncustomized
|
||||||
|
* message
|
||||||
|
*
|
||||||
|
* @return the argument, casted to have the type qualifier @NonNull at all levels
|
||||||
|
*/
|
||||||
|
private static <T extends @Nullable Object> @NonNull T @NonNull [] castNonNullArray(
|
||||||
|
T @Nullable [] arr, @Nullable String message) {
|
||||||
|
assert arr != null
|
||||||
|
: "Misuse of castNonNullArray: called with a null array argument"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
for ( int i = 0; i < arr.length; ++i ) {
|
||||||
|
assert arr[i] != null
|
||||||
|
: "Misuse of castNonNull: called with a null array element"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
checkIfArray( arr[i], message );
|
||||||
|
}
|
||||||
|
return (@NonNull T[]) arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the argument is an array, requires it to be non-null at all levels.
|
||||||
|
*
|
||||||
|
* @param ref a value; if an array, all of its elements, and their elements recursively, are
|
||||||
|
* non-null at run time
|
||||||
|
* @param message text to include if there is a non-null value, or null to use uncustomized
|
||||||
|
* message
|
||||||
|
*/
|
||||||
|
private static void checkIfArray(@NonNull Object ref, @Nullable String message) {
|
||||||
|
assert ref != null
|
||||||
|
: "Misuse of checkIfArray: called with a null argument"
|
||||||
|
+ ( ( message == null ) ? "" : ( ": " + message ) );
|
||||||
|
Class<?> comp = ref.getClass().getComponentType();
|
||||||
|
if ( comp != null ) {
|
||||||
|
// comp is non-null for arrays, otherwise null.
|
||||||
|
if ( comp.isPrimitive() ) {
|
||||||
|
// Nothing to do for arrays of primitive type: primitives are
|
||||||
|
// never null.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
castNonNullArray( (Object[]) ref, message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,10 +26,12 @@ import javax.lang.model.type.UnionType;
|
||||||
import javax.lang.model.type.WildcardType;
|
import javax.lang.model.type.WildcardType;
|
||||||
import javax.lang.model.util.SimpleTypeVisitor8;
|
import javax.lang.model.util.SimpleTypeVisitor8;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
*/
|
*/
|
||||||
public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Object> {
|
public final class TypeRenderingVisitor extends SimpleTypeVisitor8<@Nullable Object, @Nullable Object> {
|
||||||
|
|
||||||
private final StringBuilder sb = new StringBuilder();
|
private final StringBuilder sb = new StringBuilder();
|
||||||
private final Set<TypeVariable> visitedTypeVariables = new HashSet<>();
|
private final Set<TypeVariable> visitedTypeVariables = new HashSet<>();
|
||||||
|
@ -66,7 +68,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitPrimitive(PrimitiveType t, Object o) {
|
public @Nullable Object visitPrimitive(PrimitiveType t, @Nullable Object o) {
|
||||||
final String primitiveTypeName = getPrimitiveTypeName( t.getKind() );
|
final String primitiveTypeName = getPrimitiveTypeName( t.getKind() );
|
||||||
if ( primitiveTypeName != null ) {
|
if ( primitiveTypeName != null ) {
|
||||||
sb.append( primitiveTypeName );
|
sb.append( primitiveTypeName );
|
||||||
|
@ -74,7 +76,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getPrimitiveTypeName(TypeKind kind) {
|
private static @Nullable String getPrimitiveTypeName(TypeKind kind) {
|
||||||
switch ( kind ) {
|
switch ( kind ) {
|
||||||
case INT:
|
case INT:
|
||||||
return "int";
|
return "int";
|
||||||
|
@ -99,19 +101,19 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitNull(NullType t, Object o) {
|
public @Nullable Object visitNull(NullType t, @Nullable Object o) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitArray(ArrayType t, Object o) {
|
public @Nullable Object visitArray(ArrayType t, @Nullable Object o) {
|
||||||
t.getComponentType().accept( this, null );
|
t.getComponentType().accept( this, null );
|
||||||
sb.append( "[]" );
|
sb.append( "[]" );
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDeclared(DeclaredType t, Object o) {
|
public @Nullable Object visitDeclared(DeclaredType t, @Nullable Object o) {
|
||||||
sb.append( t.asElement().toString() );
|
sb.append( t.asElement().toString() );
|
||||||
List<? extends TypeMirror> typeArguments = t.getTypeArguments();
|
List<? extends TypeMirror> typeArguments = t.getTypeArguments();
|
||||||
if ( !typeArguments.isEmpty() ) {
|
if ( !typeArguments.isEmpty() ) {
|
||||||
|
@ -127,7 +129,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitTypeVariable(TypeVariable t, Object o) {
|
public @Nullable Object visitTypeVariable(TypeVariable t, @Nullable Object o) {
|
||||||
final Element typeVariableElement = t.asElement();
|
final Element typeVariableElement = t.asElement();
|
||||||
if ( typeVariableElement instanceof TypeParameterElement ) {
|
if ( typeVariableElement instanceof TypeParameterElement ) {
|
||||||
final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement;
|
final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement;
|
||||||
|
@ -145,7 +147,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitWildcard(WildcardType t, Object o) {
|
public @Nullable Object visitWildcard(WildcardType t, @Nullable Object o) {
|
||||||
sb.append( '?' );
|
sb.append( '?' );
|
||||||
if ( t.getExtendsBound() != null ) {
|
if ( t.getExtendsBound() != null ) {
|
||||||
sb.append( " extends " );
|
sb.append( " extends " );
|
||||||
|
@ -159,12 +161,12 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitUnion(UnionType t, Object o) {
|
public @Nullable Object visitUnion(UnionType t, @Nullable Object o) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitIntersection(IntersectionType t, Object o) {
|
public @Nullable Object visitIntersection(IntersectionType t, @Nullable Object o) {
|
||||||
final List<? extends TypeMirror> bounds = t.getBounds();
|
final List<? extends TypeMirror> bounds = t.getBounds();
|
||||||
bounds.get( 0 ).accept( this, null );
|
bounds.get( 0 ).accept( this, null );
|
||||||
for ( int i = 0; i < bounds.size(); i++ ) {
|
for ( int i = 0; i < bounds.size(); i++ ) {
|
||||||
|
@ -175,12 +177,12 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8<Object, Objec
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitExecutable(ExecutableType t, Object o) {
|
public @Nullable Object visitExecutable(ExecutableType t, @Nullable Object o) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitNoType(NoType t, Object o) {
|
public @Nullable Object visitNoType(NoType t, @Nullable Object o) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import javax.tools.Diagnostic;
|
||||||
import org.hibernate.jpamodelgen.Context;
|
import org.hibernate.jpamodelgen.Context;
|
||||||
import org.hibernate.jpamodelgen.MetaModelGenerationException;
|
import org.hibernate.jpamodelgen.MetaModelGenerationException;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class.
|
* Utility class.
|
||||||
*
|
*
|
||||||
|
@ -72,7 +74,7 @@ public final class TypeUtils {
|
||||||
|
|
||||||
public static String toTypeString(TypeMirror type) {
|
public static String toTypeString(TypeMirror type) {
|
||||||
if ( type.getKind().isPrimitive() ) {
|
if ( type.getKind().isPrimitive() ) {
|
||||||
return PRIMITIVE_WRAPPERS.get( type.getKind() );
|
return NullnessUtil.castNonNull( PRIMITIVE_WRAPPERS.get( type.getKind() ) );
|
||||||
}
|
}
|
||||||
return TypeRenderingVisitor.toString( type );
|
return TypeRenderingVisitor.toString( type );
|
||||||
}
|
}
|
||||||
|
@ -102,7 +104,7 @@ public final class TypeUtils {
|
||||||
return extractClosestRealTypeAsString( component, context ) + "[]";
|
return extractClosestRealTypeAsString( component, context ) + "[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeElement getSuperclassTypeElement(TypeElement element) {
|
public static @Nullable TypeElement getSuperclassTypeElement(TypeElement element) {
|
||||||
final TypeMirror superClass = element.getSuperclass();
|
final TypeMirror superClass = element.getSuperclass();
|
||||||
//superclass of Object is of NoType which returns some other kind
|
//superclass of Object is of NoType which returns some other kind
|
||||||
if ( superClass.getKind() == TypeKind.DECLARED ) {
|
if ( superClass.getKind() == TypeKind.DECLARED ) {
|
||||||
|
@ -175,7 +177,7 @@ public final class TypeUtils {
|
||||||
* @return the annotation mirror for the specified annotation class from the {@code Element} or {@code null} in case
|
* @return the annotation mirror for the specified annotation class from the {@code Element} or {@code null} in case
|
||||||
* the {@code TypeElement} does not host the specified annotation.
|
* the {@code TypeElement} does not host the specified annotation.
|
||||||
*/
|
*/
|
||||||
public static AnnotationMirror getAnnotationMirror(Element element, String fqcn) {
|
public static @Nullable AnnotationMirror getAnnotationMirror(Element element, String fqcn) {
|
||||||
assert element != null;
|
assert element != null;
|
||||||
assert fqcn != null;
|
assert fqcn != null;
|
||||||
|
|
||||||
|
@ -189,7 +191,7 @@ public final class TypeUtils {
|
||||||
return mirror;
|
return mirror;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) {
|
public static @Nullable Object getAnnotationValue(AnnotationMirror annotationMirror, String parameterValue) {
|
||||||
assert annotationMirror != null;
|
assert annotationMirror != null;
|
||||||
assert parameterValue != null;
|
assert parameterValue != null;
|
||||||
|
|
||||||
|
@ -251,7 +253,7 @@ public final class TypeUtils {
|
||||||
updateEmbeddableAccessType( searchedElement, context, defaultAccessType );
|
updateEmbeddableAccessType( searchedElement, context, defaultAccessType );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, String explicitTargetEntityName, Context context) {
|
public static TypeMirror getCollectionElementType(DeclaredType t, String fqNameOfReturnedType, @Nullable String explicitTargetEntityName, Context context) {
|
||||||
TypeMirror collectionElementType;
|
TypeMirror collectionElementType;
|
||||||
if ( explicitTargetEntityName != null ) {
|
if ( explicitTargetEntityName != null ) {
|
||||||
Elements elements = context.getElementUtils();
|
Elements elements = context.getElementUtils();
|
||||||
|
@ -300,7 +302,7 @@ public final class TypeUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AccessType getDefaultAccessForHierarchy(TypeElement element, Context context) {
|
private static @Nullable AccessType getDefaultAccessForHierarchy(TypeElement element, Context context) {
|
||||||
AccessType defaultAccessType = null;
|
AccessType defaultAccessType = null;
|
||||||
TypeElement superClass = element;
|
TypeElement superClass = element;
|
||||||
do {
|
do {
|
||||||
|
@ -370,7 +372,7 @@ public final class TypeUtils {
|
||||||
* @return returns the access type of the element annotated with the id annotation. If no element is annotated
|
* @return returns the access type of the element annotated with the id annotation. If no element is annotated
|
||||||
* {@code null} is returned.
|
* {@code null} is returned.
|
||||||
*/
|
*/
|
||||||
private static AccessType getAccessTypeInCaseElementIsRoot(TypeElement searchedElement, Context context) {
|
private static @Nullable AccessType getAccessTypeInCaseElementIsRoot(TypeElement searchedElement, Context context) {
|
||||||
List<? extends Element> myMembers = searchedElement.getEnclosedElements();
|
List<? extends Element> myMembers = searchedElement.getEnclosedElements();
|
||||||
for ( Element subElement : myMembers ) {
|
for ( Element subElement : myMembers ) {
|
||||||
List<? extends AnnotationMirror> entityAnnotations =
|
List<? extends AnnotationMirror> entityAnnotations =
|
||||||
|
@ -385,7 +387,7 @@ public final class TypeUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AccessType getAccessTypeOfIdAnnotation(Element element) {
|
private static @Nullable AccessType getAccessTypeOfIdAnnotation(Element element) {
|
||||||
AccessType accessType = null;
|
AccessType accessType = null;
|
||||||
final ElementKind kind = element.getKind();
|
final ElementKind kind = element.getKind();
|
||||||
if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) {
|
if ( kind == ElementKind.FIELD || kind == ElementKind.METHOD ) {
|
||||||
|
@ -399,13 +401,12 @@ public final class TypeUtils {
|
||||||
|| TypeUtils.isAnnotationMirrorOfType( annotationMirror, Constants.EMBEDDED_ID );
|
|| TypeUtils.isAnnotationMirrorOfType( annotationMirror, Constants.EMBEDDED_ID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AccessType determineAnnotationSpecifiedAccessType(Element element) {
|
public static @Nullable AccessType determineAnnotationSpecifiedAccessType(Element element) {
|
||||||
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Constants.ACCESS );
|
final AnnotationMirror accessAnnotationMirror = TypeUtils.getAnnotationMirror( element, Constants.ACCESS );
|
||||||
AccessType forcedAccessType = null;
|
AccessType forcedAccessType = null;
|
||||||
if ( accessAnnotationMirror != null ) {
|
if ( accessAnnotationMirror != null ) {
|
||||||
Element accessElement = (Element) TypeUtils.getAnnotationValue(
|
Element accessElement = (Element) NullnessUtil.castNonNull(
|
||||||
accessAnnotationMirror,
|
TypeUtils.getAnnotationValue( accessAnnotationMirror, DEFAULT_ANNOTATION_PARAMETER_NAME )
|
||||||
DEFAULT_ANNOTATION_PARAMETER_NAME
|
|
||||||
);
|
);
|
||||||
if ( accessElement.getKind().equals( ElementKind.ENUM_CONSTANT ) ) {
|
if ( accessElement.getKind().equals( ElementKind.ENUM_CONSTANT ) ) {
|
||||||
if ( accessElement.getSimpleName().toString().equals( AccessType.PROPERTY.toString() ) ) {
|
if ( accessElement.getSimpleName().toString().equals( AccessType.PROPERTY.toString() ) ) {
|
||||||
|
@ -436,7 +437,7 @@ public final class TypeUtils {
|
||||||
return extractClosestRealTypeAsString( typeArguments.get( 0 ), context );
|
return extractClosestRealTypeAsString( typeArguments.get( 0 ), context );
|
||||||
}
|
}
|
||||||
|
|
||||||
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor6<String, Element> {
|
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor6<@Nullable String, Element> {
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
EmbeddedAttributeVisitor(Context context) {
|
EmbeddedAttributeVisitor(Context context) {
|
||||||
|
@ -444,7 +445,7 @@ public final class TypeUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitDeclared(DeclaredType declaredType, Element element) {
|
public @Nullable String visitDeclared(DeclaredType declaredType, Element element) {
|
||||||
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
TypeElement returnedElement = (TypeElement) context.getTypeUtils().asElement( declaredType );
|
||||||
String fqNameOfReturnType = null;
|
String fqNameOfReturnType = null;
|
||||||
if ( containsAnnotation( returnedElement, Constants.EMBEDDABLE ) ) {
|
if ( containsAnnotation( returnedElement, Constants.EMBEDDABLE ) ) {
|
||||||
|
@ -454,7 +455,7 @@ public final class TypeUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitExecutable(ExecutableType t, Element p) {
|
public @Nullable String visitExecutable(ExecutableType t, Element p) {
|
||||||
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
if ( !p.getKind().equals( ElementKind.METHOD ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,10 +131,10 @@ public class JpaNamespaceTransformingEventReader extends EventReaderDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Namespace> updateElementNamespaces(StartElement startElement) {
|
private List<Namespace> updateElementNamespaces(StartElement startElement) {
|
||||||
List<Namespace> newNamespaceList = new ArrayList<Namespace>();
|
List<Namespace> newNamespaceList = new ArrayList<>();
|
||||||
Iterator<?> existingNamespaceIterator = startElement.getNamespaces();
|
Iterator<Namespace> existingNamespaceIterator = startElement.getNamespaces();
|
||||||
while ( existingNamespaceIterator.hasNext() ) {
|
while ( existingNamespaceIterator.hasNext() ) {
|
||||||
Namespace namespace = (Namespace) existingNamespaceIterator.next();
|
Namespace namespace = existingNamespaceIterator.next();
|
||||||
if ( NAMESPACE_MAPPING.containsKey( namespace.getNamespaceURI() ) ) {
|
if ( NAMESPACE_MAPPING.containsKey( namespace.getNamespaceURI() ) ) {
|
||||||
newNamespaceList.add( xmlEventFactory.createNamespace( EMPTY_PREFIX, currentDocumentNamespaceUri ) );
|
newNamespaceList.add( xmlEventFactory.createNamespace( EMPTY_PREFIX, currentDocumentNamespaceUri ) );
|
||||||
}
|
}
|
||||||
|
@ -153,10 +153,10 @@ public class JpaNamespaceTransformingEventReader extends EventReaderDelegate {
|
||||||
|
|
||||||
private List<Attribute> updateElementAttributes(StartElement startElement) {
|
private List<Attribute> updateElementAttributes(StartElement startElement) {
|
||||||
// adjust the version attribute
|
// adjust the version attribute
|
||||||
List<Attribute> newElementAttributeList = new ArrayList<Attribute>();
|
List<Attribute> newElementAttributeList = new ArrayList<>();
|
||||||
Iterator<?> existingAttributesIterator = startElement.getAttributes();
|
Iterator<Attribute> existingAttributesIterator = startElement.getAttributes();
|
||||||
while ( existingAttributesIterator.hasNext() ) {
|
while ( existingAttributesIterator.hasNext() ) {
|
||||||
Attribute attribute = (Attribute) existingAttributesIterator.next();
|
Attribute attribute = existingAttributesIterator.next();
|
||||||
if ( VERSION_ATTRIBUTE_NAME.equals( attribute.getName().getLocalPart() ) ) {
|
if ( VERSION_ATTRIBUTE_NAME.equals( attribute.getName().getLocalPart() ) ) {
|
||||||
if ( currentDocumentNamespaceUri.equals( DEFAULT_PERSISTENCE_NAMESPACE ) ) {
|
if ( currentDocumentNamespaceUri.equals( DEFAULT_PERSISTENCE_NAMESPACE ) ) {
|
||||||
if ( !DEFAULT_PERSISTENCE_VERSION.equals( attribute.getName().getPrefix() ) ) {
|
if ( !DEFAULT_PERSISTENCE_VERSION.equals( attribute.getName().getPrefix() ) ) {
|
||||||
|
|
|
@ -24,8 +24,10 @@ import javax.xml.validation.SchemaFactory;
|
||||||
|
|
||||||
import org.hibernate.jpamodelgen.Context;
|
import org.hibernate.jpamodelgen.Context;
|
||||||
import org.hibernate.jpamodelgen.util.Constants;
|
import org.hibernate.jpamodelgen.util.Constants;
|
||||||
|
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.ObjectFactory;
|
import org.hibernate.jpamodelgen.xml.jaxb.ObjectFactory;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +50,7 @@ public class XmlParserHelper {
|
||||||
|
|
||||||
private static final XMLInputFactory XML_INPUT_FACTORY = XMLInputFactory.newInstance();
|
private static final XMLInputFactory XML_INPUT_FACTORY = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
private static final ConcurrentMap<String, Schema> SCHEMA_CACHE = new ConcurrentHashMap<String, Schema>(
|
private static final ConcurrentMap<String, Schema> SCHEMA_CACHE = new ConcurrentHashMap<>(
|
||||||
NUMBER_OF_SCHEMAS
|
NUMBER_OF_SCHEMAS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ public class XmlParserHelper {
|
||||||
*
|
*
|
||||||
* @return an input stream for the specified resource or {@code null} in case resource cannot be loaded
|
* @return an input stream for the specified resource or {@code null} in case resource cannot be loaded
|
||||||
*/
|
*/
|
||||||
public InputStream getInputStreamForResource(String resource) {
|
public @Nullable InputStream getInputStreamForResource(String resource) {
|
||||||
// METAGEN-75
|
// METAGEN-75
|
||||||
if ( !resource.startsWith( RESOURCE_PATH_SEPARATOR ) ) {
|
if ( !resource.startsWith( RESOURCE_PATH_SEPARATOR ) ) {
|
||||||
resource = RESOURCE_PATH_SEPARATOR + resource;
|
resource = RESOURCE_PATH_SEPARATOR + resource;
|
||||||
|
@ -160,19 +162,17 @@ public class XmlParserHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Schema loadSchema(String schemaName) throws XmlParsingException {
|
private Schema loadSchema(String schemaName) throws XmlParsingException {
|
||||||
Schema schema = null;
|
URL schemaUrl = NullnessUtil.castNonNull( this.getClass().getClassLoader() ).getResource( schemaName );
|
||||||
URL schemaUrl = this.getClass().getClassLoader().getResource( schemaName );
|
|
||||||
if ( schemaUrl == null ) {
|
if ( schemaUrl == null ) {
|
||||||
return schema;
|
throw new IllegalArgumentException( "Couldn't find schema on classpath: " + schemaName );
|
||||||
}
|
}
|
||||||
|
|
||||||
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
|
SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
|
||||||
try {
|
try {
|
||||||
schema = sf.newSchema( schemaUrl );
|
return sf.newSchema( schemaUrl );
|
||||||
}
|
}
|
||||||
catch ( SAXException e ) {
|
catch ( SAXException e ) {
|
||||||
throw new XmlParsingException( "Unable to create schema for " + schemaName + ": " + e.getMessage(), e );
|
throw new XmlParsingException( "Unable to create schema for " + schemaName + ": " + e.getMessage(), e );
|
||||||
}
|
}
|
||||||
return schema;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ import org.hibernate.jpamodelgen.xml.jaxb.Persistence;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitDefaults;
|
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitDefaults;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitMetadata;
|
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitMetadata;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser for JPA XML descriptors (persistence.xml and referenced mapping files).
|
* Parser for JPA XML descriptors (persistence.xml and referenced mapping files).
|
||||||
*
|
*
|
||||||
|
@ -105,7 +107,7 @@ public class JpaDescriptorParser {
|
||||||
return mappingFileNames;
|
return mappingFileNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Persistence getPersistence() {
|
private @Nullable Persistence getPersistence() {
|
||||||
Persistence persistence = null;
|
Persistence persistence = null;
|
||||||
String persistenceXmlLocation = context.getPersistenceXmlLocation();
|
String persistenceXmlLocation = context.getPersistenceXmlLocation();
|
||||||
final InputStream stream = xmlParserHelper.getInputStreamForResource( persistenceXmlLocation );
|
final InputStream stream = xmlParserHelper.getInputStreamForResource( persistenceXmlLocation );
|
||||||
|
@ -249,7 +251,7 @@ public class JpaDescriptorParser {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlMetaEntity metaEntity = new XmlMetaEntity(
|
XmlMetaEntity metaEntity = XmlMetaEntity.create(
|
||||||
entity, defaultPackageName, getXmlMappedType( fqcn ), context
|
entity, defaultPackageName, getXmlMappedType( fqcn ), context
|
||||||
);
|
);
|
||||||
if ( context.containsMetaEntity( fqcn ) ) {
|
if ( context.containsMetaEntity( fqcn ) ) {
|
||||||
|
@ -333,8 +335,9 @@ public class JpaDescriptorParser {
|
||||||
|
|
||||||
private AccessType determineEntityAccessType(EntityMappings mappings) {
|
private AccessType determineEntityAccessType(EntityMappings mappings) {
|
||||||
AccessType accessType = context.getPersistenceUnitDefaultAccessType();
|
AccessType accessType = context.getPersistenceUnitDefaultAccessType();
|
||||||
if ( mappings.getAccess() != null ) {
|
final org.hibernate.jpamodelgen.xml.jaxb.AccessType mappingsAccess = mappings.getAccess();
|
||||||
accessType = mapXmlAccessTypeToJpaAccessType( mappings.getAccess() );
|
if ( mappingsAccess != null ) {
|
||||||
|
accessType = mapXmlAccessTypeToJpaAccessType( mappingsAccess );
|
||||||
}
|
}
|
||||||
return accessType;
|
return accessType;
|
||||||
}
|
}
|
||||||
|
@ -456,15 +459,11 @@ public class JpaDescriptorParser {
|
||||||
|
|
||||||
private AccessType mapXmlAccessTypeToJpaAccessType(org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType) {
|
private AccessType mapXmlAccessTypeToJpaAccessType(org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType) {
|
||||||
switch ( xmlAccessType ) {
|
switch ( xmlAccessType ) {
|
||||||
case FIELD: {
|
case FIELD:
|
||||||
return AccessType.FIELD;
|
return AccessType.FIELD;
|
||||||
}
|
case PROPERTY:
|
||||||
case PROPERTY: {
|
|
||||||
return AccessType.PROPERTY;
|
return AccessType.PROPERTY;
|
||||||
}
|
}
|
||||||
default: {
|
throw new IllegalArgumentException( "Unknown access type: " + xmlAccessType );
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.jpamodelgen.model.ImportContext;
|
||||||
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
import org.hibernate.jpamodelgen.model.MetaAttribute;
|
||||||
import org.hibernate.jpamodelgen.model.MetaEntity;
|
import org.hibernate.jpamodelgen.model.MetaEntity;
|
||||||
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
import org.hibernate.jpamodelgen.util.AccessTypeInformation;
|
||||||
|
import org.hibernate.jpamodelgen.util.NullnessUtil;
|
||||||
import org.hibernate.jpamodelgen.util.StringUtil;
|
import org.hibernate.jpamodelgen.util.StringUtil;
|
||||||
import org.hibernate.jpamodelgen.util.TypeUtils;
|
import org.hibernate.jpamodelgen.util.TypeUtils;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.Attributes;
|
import org.hibernate.jpamodelgen.xml.jaxb.Attributes;
|
||||||
|
@ -44,6 +45,8 @@ import org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.OneToMany;
|
import org.hibernate.jpamodelgen.xml.jaxb.OneToMany;
|
||||||
import org.hibernate.jpamodelgen.xml.jaxb.OneToOne;
|
import org.hibernate.jpamodelgen.xml.jaxb.OneToOne;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects XML-based meta information about an annotated type (entity, embeddable or mapped superclass).
|
* Collects XML-based meta information about an annotated type (entity, embeddable or mapped superclass).
|
||||||
*
|
*
|
||||||
|
@ -64,13 +67,13 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
private final String packageName;
|
private final String packageName;
|
||||||
private final String defaultPackageName;
|
private final String defaultPackageName;
|
||||||
private final ImportContext importContext;
|
private final ImportContext importContext;
|
||||||
private final List<MetaAttribute> members = new ArrayList<MetaAttribute>();
|
private final List<MetaAttribute> members = new ArrayList<>();
|
||||||
private final TypeElement element;
|
private final TypeElement element;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final boolean isMetaComplete;
|
private final boolean isMetaComplete;
|
||||||
|
|
||||||
private Attributes attributes;
|
private @Nullable Attributes attributes;
|
||||||
private EmbeddableAttributes embeddableAttributes;
|
private @Nullable EmbeddableAttributes embeddableAttributes;
|
||||||
private AccessTypeInformation accessTypeInfo;
|
private AccessTypeInformation accessTypeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,8 +93,13 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
this( ormEntity.getClazz(), defaultPackageName, element, context, ormEntity.isMetadataComplete() );
|
this( ormEntity.getClazz(), defaultPackageName, element, context, ormEntity.isMetadataComplete() );
|
||||||
this.attributes = ormEntity.getAttributes();
|
this.attributes = ormEntity.getAttributes();
|
||||||
this.embeddableAttributes = null;
|
this.embeddableAttributes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XmlMetaEntity create(Entity ormEntity, String defaultPackageName, TypeElement element, Context context) {
|
||||||
|
XmlMetaEntity entity = new XmlMetaEntity( ormEntity, defaultPackageName, element, context );
|
||||||
// entities can be directly initialised
|
// entities can be directly initialised
|
||||||
init();
|
entity.init();
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlMetaEntity(MappedSuperclass mappedSuperclass, String defaultPackageName, TypeElement element, Context context) {
|
XmlMetaEntity(MappedSuperclass mappedSuperclass, String defaultPackageName, TypeElement element, Context context) {
|
||||||
|
@ -125,15 +133,15 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
this.clazzName = className;
|
this.clazzName = className;
|
||||||
this.packageName = pkg;
|
this.packageName = pkg;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.importContext = new ImportContextImpl( getPackageName() );
|
this.importContext = new ImportContextImpl( pkg );
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.isMetaComplete = initIsMetaComplete( metaComplete );
|
this.isMetaComplete = initIsMetaComplete( context, metaComplete );
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void init() {
|
private final void init() {
|
||||||
context.logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
context.logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
|
||||||
|
|
||||||
this.accessTypeInfo = context.getAccessTypeInfo( getQualifiedName() );
|
this.accessTypeInfo = NullnessUtil.castNonNull( context.getAccessTypeInfo( getQualifiedName() ) );
|
||||||
if ( attributes != null ) {
|
if ( attributes != null ) {
|
||||||
parseAttributes( attributes );
|
parseAttributes( attributes );
|
||||||
}
|
}
|
||||||
|
@ -197,11 +205,11 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean initIsMetaComplete(Boolean metadataComplete) {
|
private static boolean initIsMetaComplete(Context context, Boolean metadataComplete) {
|
||||||
return context.isFullyXmlConfigured() || Boolean.TRUE.equals( metadataComplete );
|
return context.isFullyXmlConfigured() || Boolean.TRUE.equals( metadataComplete );
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getCollectionTypes(String propertyName, String explicitTargetEntity, String explicitMapKeyClass, ElementKind expectedElementKind) {
|
private @Nullable String @Nullable[] getCollectionTypes(String propertyName, String explicitTargetEntity, @Nullable String explicitMapKeyClass, ElementKind expectedElementKind) {
|
||||||
for ( Element elem : element.getEnclosedElements() ) {
|
for ( Element elem : element.getEnclosedElements() ) {
|
||||||
if ( !expectedElementKind.equals( elem.getKind() ) ) {
|
if ( !expectedElementKind.equals( elem.getKind() ) ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -226,7 +234,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeclaredType determineDeclaredType(Element elem) {
|
private @Nullable DeclaredType determineDeclaredType(Element elem) {
|
||||||
DeclaredType type = null;
|
DeclaredType type = null;
|
||||||
if ( elem.asType() instanceof DeclaredType ) {
|
if ( elem.asType() instanceof DeclaredType ) {
|
||||||
type = ( (DeclaredType) elem.asType() );
|
type = ( (DeclaredType) elem.asType() );
|
||||||
|
@ -240,17 +248,16 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] determineTypes(String propertyName, String explicitTargetEntity, String explicitMapKeyClass, DeclaredType type) {
|
private @Nullable String[] determineTypes(String propertyName, String explicitTargetEntity, @Nullable String explicitMapKeyClass, DeclaredType type) {
|
||||||
String[] types = new String[3];
|
@Nullable String[] types = new String[3];
|
||||||
determineTargetType( type, propertyName, explicitTargetEntity, types );
|
determineTargetType( type, propertyName, explicitTargetEntity, types );
|
||||||
determineCollectionType( type, types );
|
if ( determineCollectionType( type, types ).equals( "jakarta.persistence.metamodel.MapAttribute" ) ) {
|
||||||
if ( types[1].equals( "jakarta.persistence.metamodel.MapAttribute" ) ) {
|
|
||||||
determineMapType( type, explicitMapKeyClass, types );
|
determineMapType( type, explicitMapKeyClass, types );
|
||||||
}
|
}
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void determineMapType(DeclaredType type, String explicitMapKeyClass, String[] types) {
|
private void determineMapType(DeclaredType type, @Nullable String explicitMapKeyClass, @Nullable String[] types) {
|
||||||
if ( explicitMapKeyClass != null ) {
|
if ( explicitMapKeyClass != null ) {
|
||||||
types[2] = explicitMapKeyClass;
|
types[2] = explicitMapKeyClass;
|
||||||
}
|
}
|
||||||
|
@ -259,11 +266,11 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void determineCollectionType(DeclaredType type, String[] types) {
|
private String determineCollectionType(DeclaredType type, @Nullable String[] types) {
|
||||||
types[1] = COLLECTIONS.get( type.asElement().toString() );
|
return NullnessUtil.castNonNull( types[1] = COLLECTIONS.get( type.asElement().toString() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void determineTargetType(DeclaredType type, String propertyName, String explicitTargetEntity, String[] types) {
|
private void determineTargetType(DeclaredType type, String propertyName, String explicitTargetEntity, @Nullable String[] types) {
|
||||||
List<? extends TypeMirror> typeArguments = type.getTypeArguments();
|
List<? extends TypeMirror> typeArguments = type.getTypeArguments();
|
||||||
|
|
||||||
if ( typeArguments.size() == 0 && explicitTargetEntity == null ) {
|
if ( typeArguments.size() == 0 && explicitTargetEntity == null ) {
|
||||||
|
@ -288,7 +295,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
* @return The entity type for this property or {@code null} if the property with the name and the matching access
|
* @return The entity type for this property or {@code null} if the property with the name and the matching access
|
||||||
* type does not exist.
|
* type does not exist.
|
||||||
*/
|
*/
|
||||||
private String getType(String propertyName, String explicitTargetEntity, ElementKind expectedElementKind) {
|
private @Nullable String getType(String propertyName, @Nullable String explicitTargetEntity, ElementKind expectedElementKind) {
|
||||||
for ( Element elem : element.getEnclosedElements() ) {
|
for ( Element elem : element.getEnclosedElements() ) {
|
||||||
if ( !expectedElementKind.equals( elem.getKind() ) ) {
|
if ( !expectedElementKind.equals( elem.getKind() ) ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -413,7 +420,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseEmbeddableAttributes(EmbeddableAttributes attributes) {
|
private void parseEmbeddableAttributes(@Nullable EmbeddableAttributes attributes) {
|
||||||
if ( attributes == null ) {
|
if ( attributes == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -449,7 +456,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseElementCollection(ElementCollection collection) {
|
private boolean parseElementCollection(ElementCollection collection) {
|
||||||
String[] types;
|
@Nullable String @Nullable[] types;
|
||||||
XmlMetaCollection metaCollection;
|
XmlMetaCollection metaCollection;
|
||||||
ElementKind elementKind = getElementKind( collection.getAccess() );
|
ElementKind elementKind = getElementKind( collection.getAccess() );
|
||||||
String explicitTargetClass = determineExplicitTargetEntity( collection.getTargetClass() );
|
String explicitTargetClass = determineExplicitTargetEntity( collection.getTargetClass() );
|
||||||
|
@ -464,11 +471,14 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( types != null ) {
|
if ( types != null ) {
|
||||||
if ( types[2] == null ) {
|
final String type = NullnessUtil.castNonNull( types[0] );
|
||||||
metaCollection = new XmlMetaCollection( this, collection.getName(), types[0], types[1] );
|
final String collectionType = NullnessUtil.castNonNull( types[1] );
|
||||||
|
final String keyType = types[2];
|
||||||
|
if ( keyType == null ) {
|
||||||
|
metaCollection = new XmlMetaCollection( this, collection.getName(), type, collectionType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
metaCollection = new XmlMetaMap( this, collection.getName(), types[0], types[1], types[2] );
|
metaCollection = new XmlMetaMap( this, collection.getName(), type, collectionType, keyType );
|
||||||
}
|
}
|
||||||
members.add( metaCollection );
|
members.add( metaCollection );
|
||||||
}
|
}
|
||||||
|
@ -495,7 +505,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return explicitTargetClass;
|
return explicitTargetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String determineExplicitMapKeyClass(MapKeyClass mapKeyClass) {
|
private @Nullable String determineExplicitMapKeyClass(MapKeyClass mapKeyClass) {
|
||||||
String explicitMapKey = null;
|
String explicitMapKey = null;
|
||||||
if ( mapKeyClass != null ) {
|
if ( mapKeyClass != null ) {
|
||||||
explicitMapKey = StringUtil.determineFullyQualifiedClassName( defaultPackageName, mapKeyClass.getClazz() );
|
explicitMapKey = StringUtil.determineFullyQualifiedClassName( defaultPackageName, mapKeyClass.getClazz() );
|
||||||
|
@ -504,7 +514,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseOneToMany(OneToMany oneToMany) {
|
private boolean parseOneToMany(OneToMany oneToMany) {
|
||||||
String[] types;
|
@Nullable String @Nullable [] types;
|
||||||
XmlMetaCollection metaCollection;
|
XmlMetaCollection metaCollection;
|
||||||
ElementKind elementKind = getElementKind( oneToMany.getAccess() );
|
ElementKind elementKind = getElementKind( oneToMany.getAccess() );
|
||||||
String explicitTargetClass = determineExplicitTargetEntity( oneToMany.getTargetEntity() );
|
String explicitTargetClass = determineExplicitTargetEntity( oneToMany.getTargetEntity() );
|
||||||
|
@ -517,11 +527,14 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( types != null ) {
|
if ( types != null ) {
|
||||||
if ( types[2] == null ) {
|
final String type = NullnessUtil.castNonNull( types[0] );
|
||||||
metaCollection = new XmlMetaCollection( this, oneToMany.getName(), types[0], types[1] );
|
final String collectionType = NullnessUtil.castNonNull( types[1] );
|
||||||
|
final String keyType = types[2];
|
||||||
|
if ( keyType == null ) {
|
||||||
|
metaCollection = new XmlMetaCollection( this, oneToMany.getName(), type, collectionType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
metaCollection = new XmlMetaMap( this, oneToMany.getName(), types[0], types[1], types[2] );
|
metaCollection = new XmlMetaMap( this, oneToMany.getName(), type, collectionType, keyType );
|
||||||
}
|
}
|
||||||
members.add( metaCollection );
|
members.add( metaCollection );
|
||||||
}
|
}
|
||||||
|
@ -529,7 +542,7 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseManyToMany(ManyToMany manyToMany) {
|
private boolean parseManyToMany(ManyToMany manyToMany) {
|
||||||
String[] types;
|
@Nullable String @Nullable [] types;
|
||||||
XmlMetaCollection metaCollection;
|
XmlMetaCollection metaCollection;
|
||||||
ElementKind elementKind = getElementKind( manyToMany.getAccess() );
|
ElementKind elementKind = getElementKind( manyToMany.getAccess() );
|
||||||
String explicitTargetClass = determineExplicitTargetEntity( manyToMany.getTargetEntity() );
|
String explicitTargetClass = determineExplicitTargetEntity( manyToMany.getTargetEntity() );
|
||||||
|
@ -544,11 +557,14 @@ public class XmlMetaEntity implements MetaEntity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( types != null ) {
|
if ( types != null ) {
|
||||||
if ( types[2] == null ) {
|
final String type = NullnessUtil.castNonNull( types[0] );
|
||||||
metaCollection = new XmlMetaCollection( this, manyToMany.getName(), types[0], types[1] );
|
final String collectionType = NullnessUtil.castNonNull( types[1] );
|
||||||
|
final String keyType = types[2];
|
||||||
|
if ( keyType == null ) {
|
||||||
|
metaCollection = new XmlMetaCollection( this, manyToMany.getName(), type, collectionType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
metaCollection = new XmlMetaMap( this, manyToMany.getName(), types[0], types[1], types[2] );
|
metaCollection = new XmlMetaMap( this, manyToMany.getName(), type, collectionType, keyType );
|
||||||
}
|
}
|
||||||
members.add( metaCollection );
|
members.add( metaCollection );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue