LazyPropertyInitializer type casting error

Project architecture:spring, springMVC,hibernate
Project Architecture Upgrade:

  • JDK 8 to JDK 17
  • Spring 5.2 to Spring 6.1.5
  • Hibernate 5.3 to Hibernate 6.2.25
  • Tomcat 8 to Tomcat 10
    Error Information:class org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer$1 cannot be cast to class java.lang.String (org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer$1 is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @acdb094; java.lang.String is in module java.base of loader ‘bootstrap’)

Code structure:
public abstract class BaseModel implements IBaseModel, Serializable {

protected transient PersistentAttributeInterceptor interceptor;

private CustomPropList<Map<String, Object>> customPropList = new CustomPropList<Map<String, Object>>();

@SuppressWarnings("unused")
private Map<String, Object> customPropMap = customPropList.getCustomPropMap();

protected SysDictModel sysDictModel;

protected String fdId;

@Override
public String getFdId() {
    if (fdId == null) {
        fdId = IDGenerator.generateID();
    }
    return fdId;
}

@Override
public void setFdId(String id) {
    this.fdId = id;
}

@Override
public void recalculateFields() {

}

@Override
public ModelToFormPropertyMap getToFormPropertyMap() {
    return new ModelToFormPropertyMap();
}

/**
 *
 * @see Object#toString()
 */
@Override
public String toString() {
    try {
        PersistentClass persistentClass = HibernateUtil.getPersistentClass(this.getClass());
        Method[] methodList = this.getClass().getMethods();
        ToStringBuilder rtnVal = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
        for (int i = 0; i < methodList.length; i++) {
            String methodName = methodList[i].getName();
            if (methodList[i].getParameterTypes().length > 0 || !methodName.startsWith("get")
                    || "getClass".equals(methodName)) {
                continue;
            }
            methodName = methodList[i].getReturnType().toString();
            if ((methodName.startsWith("class") || methodName.startsWith("interface"))
                    && !(methodName.startsWith("class java.lang.")
                    || methodName.startsWith("interface java.lang."))) {
                continue;
            }
            methodName = methodList[i].getName();
            String propertyName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
            if (persistentClass.hasProperty(propertyName)
                    && persistentClass.getProperty(propertyName).isLazy()) {
                continue;
            }
            try {
                rtnVal.append(methodList[i].getName().substring(3), methodList[i].invoke(this, null));
            } catch (Exception e) {
            }
        }
        return rtnVal.toString().replaceAll("@[^\\[]+\\[\\r\\n", "[\r\n");
    } catch (Exception e) {
        return super.toString();
    }
}

/**
 * @see Object#equals(Object)
 */
@Override
public boolean equals(Object object) {
    if (this == object) {
        return true;
    }
    if (object == null) {
        return false;
    }
    if (!ModelUtil.getModelClassName(object).equals(ModelUtil.getModelClassName(this))) {
        return false;
    }
    BaseModel objModel = (BaseModel) object;
    return ObjectUtil.equals(objModel.getFdId(), this.getFdId(), false);
}

/**
 * @see Object#hashCode()
 */
@Override
public int hashCode() {
    HashCodeBuilder rtnVal = new HashCodeBuilder(-426830461, 631494429);
    rtnVal.append(ModelUtil.getModelClassName(this));
    rtnVal.append(getFdId());
    return rtnVal.toHashCode();
}

@SuppressWarnings("unchecked")
protected Object readLazyField(String fieldName, Object oldValue) {
    if (null != interceptor) {
        oldValue = interceptor.readObject(this, fieldName, oldValue);
    }
    return oldValue;
}

protected Object writeLazyField(String fieldName, Object oldValue, Object newValue) {
    if (null == interceptor) {
        return newValue;
    }

    return interceptor.writeObject(this, fieldName, oldValue, newValue);
}

@JsonIgnore
public PersistentAttributeInterceptor $$_hibernate_getInterceptor() {
    return interceptor;
}

public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor interceptor) {
    this.interceptor = interceptor;
}

@Override
public SysDictModel getSysDictModel() {
    return sysDictModel;
}

@Override
public void setSysDictModel(SysDictModel sysDictModel) {
    this.sysDictModel = sysDictModel;
}

public Map<String, String> dynamicMap = new HashMap<String, String>();

@Override
public Map<String, String> getDynamicMap() {
    return dynamicMap;
}

public void setDynamicMap(Map<String, String> dynamicMap) {
    this.dynamicMap = dynamicMap;
}

/**
 * please use  getCustomPropList
 *
 * @return
 */
@Override
public Map<String, Object> getCustomPropMap() {
    return this.customPropList.getCustomPropMap();

}

/**
 * please use  setCustomPropList
 *
 * @param customPropMap
 */
public void setCustomPropMap(Map<String, Object> customPropMap) {
    this.customPropMap = customPropMap;
    this.customPropList.setCustomPropMap(customPropMap);
}

public CustomPropList<Map<String, Object>> getCustomPropList() {
    return this.customPropList;
}

public void setCustomPropList(CustomPropList<Map<String, Object>> customPropList) {
    this.customPropList = customPropList;
}

/**
 */
private Map<String, Object> mechanismMap = new HashMap<>();

@Override
public Map<String, Object> getMechanismMap() {
    return mechanismMap;
}

@Override
public void setMechanismMap(Map<String, Object> mechanismMap) {
    this.mechanismMap = mechanismMap;
}

@JsonIgnore
private transient Map<String, Object> transientInfoMap = new HashMap<>();

/**
 * @return
 */
@Override
public Map<String, Object> getTransientInfoMap(){
    return transientInfoMap;
}

@Override
public void setTransientInfoMap(Map<String, Object> transientInfoMap){
    this.transientInfoMap = transientInfoMap;
}

}

public class SysPortalPageDetail extends BaseModel implements IBaseModel,
InterceptFieldEnabled {
protected SysPortalPage sysPortalPage;
protected String fdType;
protected String docContent;
protected String fdMd5;
protected String fdJsp;
protected String fdHeader;
protected String fdFooter;
protected String fdLogo;
protected String fdHeaderVars;
protected String fdFooterVars;
protected String fdGuide;
protected String fdGuideCfg;

public String getFdType() {
	return fdType;
}

public void setFdType(String fdType) {
	this.fdType = fdType;
}

public SysPortalPage getSysPortalPage() {
	return sysPortalPage;
}

public void setSysPortalPage(SysPortalPage sysPortalPage) {
	this.sysPortalPage = sysPortalPage;
}

/**
 */
public String getDocContent() {
	return (String) readLazyField("docContent", docContent);
}

/**
 * @param docContent
 */
public void setDocContent(String docContent) {
	this.docContent = (String) writeLazyField("docContent",
			this.docContent, docContent);
}

public String getFdHeaderVars() {
	return fdHeaderVars;
}

public void setFdHeaderVars(String fdHeaderVars) {
	this.fdHeaderVars = fdHeaderVars;
}

public String getFdFooterVars() {
	return fdFooterVars;
}

public void setFdFooterVars(String fdFooterVars) {
	this.fdFooterVars = fdFooterVars;
}

public String getFdLogo() {
	return fdLogo;
}

public void setFdLogo(String fdLogo) {
	this.fdLogo = fdLogo;
}

public String getFdHeader() {
	return fdHeader;
}

public void setFdHeader(String fdHeader) {
	this.fdHeader = fdHeader;
}

public String getFdFooter() {
	return fdFooter;
}

public void setFdFooter(String fdFooter) {
	this.fdFooter = fdFooter;
}

public String getFdJsp() {
	return (String) readLazyField("fdJsp", fdJsp);
}

public void setFdJsp(String fdJsp) {
	this.fdJsp = (String) writeLazyField("fdJsp", this.fdJsp, fdJsp);
}

public String getFdMd5() {
	return fdMd5;
}

public void setFdMd5(String fdMd5) {
	this.fdMd5 = fdMd5;
}

public String getFdGuide() {
	return fdGuide;
}

public void setFdGuide(String fdGuide) {
	this.fdGuide = fdGuide;
}

public String getFdGuideCfg() {
	return (String) readLazyField("fdGuideCfg", fdGuideCfg);
}

public void setFdGuideCfg(String fdGuideCfg) {
	this.fdGuideCfg = (String) writeLazyField("fdGuideCfg",
			this.fdGuideCfg, fdGuideCfg);
}

@Override
public Class getFormClass() {
	return SysPortalPageDetailForm.class;
}

private static ModelToFormPropertyMap toFormPropertyMap;

@Override
public ModelToFormPropertyMap getToFormPropertyMap() {
	if (toFormPropertyMap == null) {
		toFormPropertyMap = new ModelToFormPropertyMap();
		toFormPropertyMap.putAll(super.getToFormPropertyMap());
		toFormPropertyMap.put("sysPortalPage.fdId", "sysPortalPageId");
	}
	return toFormPropertyMap;
}

}

<?xml version="1.0" encoding="UTF-8"?>
	<property
		name="docContent"
		column="doc_content"
		update="true"
		insert="true"
		length="1000000"
		not-null="false"
		type="com.landray.kmss.common.dao.ClobStringType"
		lazy="true" />

	<property
		name="fdJsp"
		column="fd_jsp"
		update="true"
		insert="true"
		length="1000000"
		not-null="false"
		type="com.landray.kmss.common.dao.ClobStringType"
		lazy="true" />

	<property
		name="fdMd5"
		column="fd_md5"
		update="true"
		insert="true"
		length="36"
		not-null="false" />

	<property
		name="fdHeader"
		column="fd_header"
		update="true"
		insert="true"
		length="255"
		not-null="false" />

	<property
		name="fdFooter"
		column="fd_footer"
		update="true"
		insert="true"
		length="255"
		not-null="false" />

	<property
		name="fdLogo"
		column="fd_logo"
		update="true"
		insert="true"
		length="255"
		not-null="false" />

	<property
		name="fdFooterVars"
		column="fd_footer_vars"
		update="true"
		insert="true"
		length="999"
		not-null="false" />

	<property
		name="fdHeaderVars"
		column="fd_header_vars"
		update="true"
		insert="true"
		length="999"
		not-null="false" />
	
	<property
		name="fdGuide"
		column="fd_guide"
		update="true"
		insert="true"
		length="255"
		not-null="false" />	
		
	<property
		name="fdGuideCfg"
		column="fd_guide_cfg"
		update="true"
		insert="true"
		length="1000000"
		not-null="false"
		type="com.landray.kmss.common.dao.ClobStringType"
		lazy="true" />	

	<property
		name="fdType"
		column="fd_type"
		update="true"
		insert="true"
		length="20"
		not-null="false" />

	<many-to-one
		name="sysPortalPage"
		column="fd_page_id"
		insert="true"
		update="true"
		not-null="false" />
</class>
Hibernate 6.2 added the code for `ReflectionOptimizer.AccessOptimizer` , which causes it to always go through the `setPropertyValues` method. This part of the code was not present in Hibernate 5.3, and the application ran normally.

This issue occurred after the architecture upgrade. Since the concept of modularity was introduced after JDK 9, is there a solution in Hibernate that can be compatible with this adjustment? Please provide the cause of the error mentioned above and suggest a solution. Thank you.

This is simply a bug. Please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.

The issue has been reproduced through your test case template:

Please provide relevant suggestions and solutions, this issue is likely a bug in Hibernate.

Additional Information:

Just create a Jira issue for this bug and attach a ZIP file with the reproducer or share a link to the GitHub repository branch containing the code.

Due to the security requirements of the company, the project cannot be placed on GitHub. Can we try to reproduce and analyze it internally?

You only have to share the reproducer, not your company application.