关于Query Dsl实体类4个层级时空指针问题。

本文dsl实体类由apt-maven-plugin build生成。

我们以四个实体类School, Clazz, Course, User为例。其中User类包含Course类,以此类推,逐层包含。

首先以QUser类为例来看内部实体对象的构建。只贴出了解读用到的代码。

public class QUser extends EntityPathBase<User> {

    private static final PathInits INITS = PathInits.DIRECT2;

    public static final QUser user = new QUser("user");

    public QUser(String variable) {
        this(User.class, forVariable(variable), INITS);
    }

    public QUser(Class<? extends User> type, PathMetadata metadata, PathInits inits) {
        super(type, metadata, inits);
        this.course = inits.isInitialized("course") ? new QCourse(forProperty("course"), inits.get("course")) : null;
    }
}

我们可以看到,Q类的PathInits为PathInits.DIRECT2。当调用Q类的只有PathMetadata的构造参数时,会调用PathInits.getFor(metadata, INITS)方法。而当我们创建Q类时,只有Pathinits.isInitialized()==false时,内部实体对象才为空。

此时我们来看PathInits.DIRECT2的构造方法。

public class PathInits implements Serializable {

    private static final long serialVersionUID = -2173980858324141095L;

    public static final PathInits DEFAULT = new PathInits();

    public static final PathInits DIRECT  = new PathInits("*");

    public static final PathInits DIRECT2  = new PathInits("*.*");

    private final boolean initAllProps;

    private final PathInits defaultValue;

    private final Map<String,PathInits> propertyToInits = new HashMap<String,PathInits>();

    public PathInits(String... initStrs) {
        boolean initAllProps = false;
        PathInits defaultValue = DEFAULT;

        Map<String, Collection<String>> properties = Maps.newHashMap();
        for (String initStr : initStrs) {
            if (initStr.equals("*")) {
                initAllProps = true;
            } else if (initStr.startsWith("*.")) {
                initAllProps = true;
                defaultValue = new PathInits(initStr.substring(2));
            } else {
                String key = initStr;
                List<String> inits = Collections.emptyList();
                if (initStr.contains(".")) {
                    key = initStr.substring(0, initStr.indexOf('.'));
                    inits = ImmutableList.of(initStr.substring(key.length() + 1));
                }
                Collection<String> values = properties.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    properties.put(key, values);
                }
                values.addAll(inits);
            }
        }

        for (Map.Entry<String, Collection<String>> entry : properties.entrySet()) {
            PathInits inits = new PathInits(Iterables.toArray(entry.getValue(), String.class));
            propertyToInits.put(entry.getKey(), inits);
        }

        this.initAllProps = initAllProps;
        this.defaultValue = defaultValue;
    }
}

构造之后的对象如下:

而当初始化QUser时,其内部的对象course对应的QCourse的PathInits为inits.get("course"),我们来看PathInits.get()方法

    public PathInits get(String property) {
        if (propertyToInits.containsKey(property)) {
            return propertyToInits.get(property);
        } else if (initAllProps) {
            return defaultValue;
        } else {
            throw new IllegalArgumentException(property + " is not initialized");
        }
    }

由于propertyToInits为空,所以返回QUser.inits.defaultVaue,即上图中的PathInits@8473,同样QCourse中的clazz PathInits为@8475,而此时initAllProps == false, propertyToInits为空。此时来看Pathinits.isInitialized()方法

public boolean isInitialized(String property) {
        return initAllProps || propertyToInits.containsKey(property);
}

此时可以看到,此方法返回false,所以clazz中的school为null, 所以四层实体类对象为空。

猜你喜欢

转载自blog.csdn.net/wqc8994/article/details/107432227