Hibernate Envers为修订加载延迟实体

时间:2017-11-09 11:03:49

标签: java spring hibernate hibernate-envers

我正在使用Spring Boot,Spring Data REST,Spring HATEOAS,Hibernate,Spring Data Envers。 我正在审核我的实体,以便跟踪所有更改。我正在从Angular 4应用程序中使用REST服务。 我的目标是为每个修订版(envers)显示一个框的lix,仅显示修改后的属性。

我的实体注释了@Audited。这是我的模特:

@Audited
public class LicensePlate extends AbstractEntity {
    private static final long serialVersionUID = -6871697166535810224L;

    @NotEmpty
    @ColumnTransformer(read = "UPPER(licensePlate)", write = "UPPER(?)")
    @Column(nullable = false, unique = true)
    private String licensePlate;    

    @NotNull
    @Range(min = 1, max = 99)
    @Column(nullable = false, columnDefinition = "INTEGER default 50")
    private int seats = 50;


    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Country country;

正如你所看到的,Country是LAZY,我不能把它设置为EAGER。

我发现这个类以递归方式检查模型中的延迟属性并初始化它们。

public class HibernateUtil {

    public static byte[] hibernateCollectionPackage = "org.hibernate.collection".getBytes();

    public static void initializeObject(Object o, String insidePackageName) {
        Set<Object> seenObjects = new HashSet<Object>();
        initializeObject(o, seenObjects, insidePackageName.getBytes());
        seenObjects = null;
    }

    private static void initializeObject(Object o, Set<Object> seenObjects, byte[] insidePackageName) {

        seenObjects.add(o);

        Method[] methods = o.getClass().getMethods();
        for (Method method : methods) {

            String methodName = method.getName();

            // check Getters exclusively
            if (methodName.length() < 3 || !"get".equals(methodName.substring(0, 3)))
                continue;

            // Getters without parameters
            if (method.getParameterTypes().length > 0)
                continue;

            int modifiers = method.getModifiers();

            // Getters that are public
            if (!Modifier.isPublic(modifiers))
                continue;

            // but not static
            if (Modifier.isStatic(modifiers))
                continue;

            try {

                // Check result of the Getter
                Object r = method.invoke(o);

                if (r == null)
                    continue;

                // prevent cycles
                if (seenObjects.contains(r))
                    continue;

                // ignore simple types, arrays und anonymous classes
                if (!isIgnoredType(r.getClass()) && !r.getClass().isPrimitive() && !r.getClass().isArray()
                        && !r.getClass().isAnonymousClass()) {

                    // ignore classes out of the given package and out of the
                    // hibernate collection
                    // package
                    if (!isClassInPackage(r.getClass(), insidePackageName) && !isClassInPackage(r.getClass(), hibernateCollectionPackage)) {
                        continue;
                    }

                    // initialize child object
                    Hibernate.initialize(r);

                    // traverse over the child object
                    initializeObject(r, seenObjects, insidePackageName);
                }

            } catch (InvocationTargetException e) {
                e.printStackTrace();
                return;
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                return;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return;
            }
        }

    }

    private static final Set<Class<?>> IGNORED_TYPES = getIgnoredTypes();

    private static boolean isIgnoredType(Class<?> clazz) {
        return IGNORED_TYPES.contains(clazz);
    }

    private static Set<Class<?>> getIgnoredTypes() {
        Set<Class<?>> ret = new HashSet<Class<?>>();
        ret.add(Boolean.class);
        ret.add(Character.class);
        ret.add(Byte.class);
        ret.add(Short.class);
        ret.add(Integer.class);
        ret.add(Long.class);
        ret.add(Float.class);
        ret.add(Double.class);
        ret.add(Void.class);
        ret.add(String.class);
        ret.add(Class.class);
        ret.add(Package.class);
        return ret;
    }

    private static Boolean isClassInPackage(Class<?> clazz, byte[] insidePackageName) {

        Package p = clazz.getPackage();
        if (p == null)
            return null;

        byte[] packageName = p.getName().getBytes();

        int lenP = packageName.length;
        int lenI = insidePackageName.length;

        if (lenP < lenI)
            return false;

        for (int i = 0; i < lenI; i++) {
            if (packageName[i] != insidePackageName[i])
                return false;
        }

        return true;
    }
}

这是REST控制器:

    @PreAuthorize("isAuthenticated()")
    @RequestMapping(value = "/licensePlates/{id}/revisions/{revid}", method = RequestMethod.GET)
    public ResponseEntity<?> findRevision(@PathVariable(value = "id") Long id, @PathVariable(value = "revid") Integer revId,
            Pageable pageable) {
        if (id != null) {
            List<RestChange> changes = new ArrayList<>();

            AuditReader reader = AuditReaderFactory.get(entityManager);
            AuditQuery q = reader.createQuery().forEntitiesAtRevision(LicensePlate.class, revId);
            LicensePlate current = (LicensePlate) q.getSingleResult();
            HibernateUtil.initializeObject(current, "it.model");

            //PREVIOUS
            if (revId > 1) {
                q = reader.createQuery().forEntitiesAtRevision(LicensePlate.class, revId - 1);
                LicensePlate previous = (LicensePlate) q.getSingleResult();             
                HibernateUtil.initializeObject(previous, "it.model");

                Diff diff = javers.compare(previous, current);
                for (Change change : diff.getChanges()) {
                    log.debug("Change: " + change);
                    if (change instanceof ValueChange) {
                        ValueChange c = (ValueChange) change;
                        RestChange restChange = new RestChange();
                        restChange.setPropertyName(c.getPropertyName());
                        restChange.setPreviousValue(c.getLeft());
                        restChange.setValue(c.getRight());
                        changes.add(restChange);
                    } else if (change instanceof ReferenceChange) {
                        ReferenceChange c = (ReferenceChange) change;
                        RestChange restChange = new RestChange();
                        restChange.setPropertyName(c.getPropertyName());
                        restChange.setPreviousValue(c.getLeftObject().get().toString());
                        restChange.setValue(c.getRightObject().get().toString());
                        changes.add(restChange);
                    }

                }
            }


            return new ResponseEntity<>(new Resources<>(changes), HttpStatus.OK);
        } else {
            throw new ResourceNotFoundException();
        }
    }

我调试了,即使在调用Hibernate.initialize之后,countrycurrent bean中的属性previous仍然是代理。我找到解决问题的唯一方法是调用Hibernate.initialize(current.getCountry()),然后重新设置licensePlate bean中的值,但我觉得这不对。

我用类似的问题检查了所有其他问题,并且在所有情况下Hibernate.initialize都是问题的解决方案,但是这里似乎不起作用。 我做错了什么?

0 个答案:

没有答案