FTS: Cannot get unfetched attribute

Updated to 6.9.5 , FTS suddenly stopped to work. Last time I tested it with no issues. This happens to me once time ago, and it solved alone the next day.

But this time it remains and through an error:

java.lang.IllegalStateException: Cannot get unfetched attribute [codigoProveedor] from detached object com.company.myerp.entity.Proveedor-e642bc8e-d573-9c26-68a8-a2e35a309991 [detached].
	at org.eclipse.persistence.internal.queries.EntityFetchGroup.onUnfetchedAttribute(EntityFetchGroup.java:98)
	at com.haulmont.cuba.core.sys.persistence.CubaEntityFetchGroup.onUnfetchedAttribute(CubaEntityFetchGroup.java:74)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.processUnfetchedAttribute(EntityManagerImpl.java:2846)
	at com.haulmont.chile.core.model.impl.AbstractInstance._persistence_checkFetched(AbstractInstance.java)
	at com.company.myerp.entity.Proveedor._persistence_get_codigoProveedor(Proveedor.java)
	at com.company.myerp.entity.Proveedor.getCodigoProveedor(Proveedor.java:38)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.haulmont.chile.core.model.utils.MethodsCache.invokeGetter(MethodsCache.java:72)
	at com.haulmont.chile.core.model.impl.AbstractInstance.getValue(AbstractInstance.java:102)
	at com.haulmont.cuba.core.entity.BaseGenericIdEntity.getValue(BaseGenericIdEntity.java:139)
	at com.haulmont.chile.core.model.utils.InstanceUtils.getInstanceName(InstanceUtils.java:235)
	at com.haulmont.chile.core.model.impl.AbstractInstance.getInstanceName(AbstractInstance.java:59)
	at com.haulmont.fts.core.app.FtsServiceBean.createEntry(FtsServiceBean.java:215)
	at com.haulmont.fts.core.app.FtsServiceBean.makeSearchResult(FtsServiceBean.java:141)
	at com.haulmont.fts.core.app.FtsServiceBean.search(FtsServiceBean.java:70)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:117)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy291.search(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.haulmont.cuba.core.sys.remoting.LocalServiceInvokerImpl.invoke(LocalServiceInvokerImpl.java:94)
	at com.haulmont.cuba.web.sys.remoting.LocalServiceProxy$LocalServiceInvocationHandler.invoke(LocalServiceProxy.java:154)
	at com.sun.proxy.$Proxy73.search(Unknown Source)
	at com.haulmont.fts.web.ui.results.SearchLauncher.call(SearchLauncher.java:44)
	at com.haulmont.fts.web.ui.results.SearchLauncher.call(SearchLauncher.java:22)
	at com.haulmont.cuba.gui.WindowManager.createWindowByScreenClass(WindowManager.java:721)
	at com.haulmont.cuba.gui.WindowManager.openWindow(WindowManager.java:762)
	at com.haulmont.cuba.web.WebWindowManager.openWindow(WebWindowManager.java:158)
	at com.haulmont.cuba.gui.components.WindowDelegate.openWindow(WindowDelegate.java:235)
	at com.haulmont.cuba.web.gui.WebWindow.openWindow(WebWindow.java:464)
	at com.haulmont.cuba.web.gui.components.mainwindow.WebFtsField.openSearchWindow(WebFtsField.java:88)
	at com.haulmont.cuba.web.gui.components.mainwindow.WebFtsField$1.handleAction(WebFtsField.java:64)
	at com.vaadin.event.ActionManager.handleAction(ActionManager.java:250)
	at com.vaadin.event.ActionManager.handleActions(ActionManager.java:228)
	at com.haulmont.cuba.web.toolkit.ui.CubaTextField.changeVariables(CubaTextField.java:80)

The stack trace shows that related attribute used in the instance name (@NamePattern) is not fetched for some reason. Could you provide the source code of the entities in question?

Entity Proveedor extends from entity Tercero. Field codigoProveedor is exclusive from Proveedor and is part of @NamePattern, but not on entity Tercero. The search result is about field razonSocial, extended from Tercero,

Tercero:
 import javax.persistence.Entity;
 import javax.persistence.Table;
 import javax.persistence.Column;
 import com.haulmont.cuba.core.entity.StandardEntity;
 import com.haulmont.chile.core.annotations.NamePattern;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.validation.constraints.NotNull;
 import com.haulmont.cuba.core.entity.annotation.Lookup;
 import com.haulmont.cuba.core.entity.annotation.LookupType;
 import java.util.List;
 import javax.persistence.OneToMany;
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.DiscriminatorType;
 import javax.persistence.DiscriminatorColumn;
 import javax.persistence.MappedSuperclass;
 import javax.persistence.Lob;
 import com.haulmont.chile.core.annotations.Composition;
 import com.haulmont.cuba.core.entity.annotation.OnDelete;
 import com.haulmont.cuba.core.global.DeletePolicy;
 import javax.persistence.InheritanceType;
 import javax.persistence.Inheritance;
 import com.haulmont.cuba.core.entity.FileDescriptor;
 import javax.persistence.OneToOne;
 import java.util.Date;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 import java.math.BigDecimal;
 
 @DiscriminatorColumn(name = "DTYPE", discriminatorType = DiscriminatorType.STRING)
 @Inheritance(strategy = InheritanceType.JOINED)
 @NamePattern("%s|nombre")
 @Table(name = "MYAPP_TERCERO")
 @Entity(name = "myapp$Tercero")
 public class Tercero extends StandardEntity {
     private static final long serialVersionUID = 7592958065911310778L;
 
     @Column(name = "NOMBRE", length = 100)
     protected String nombre;
 
     @Column(name = "CIF", length = 20)
     protected String cif;
 
     @NotNull
     @Column(name = "RAZON_SOCIAL", nullable = false, length = 100)
     protected String razonSocial;
 
     @Column(name = "APODO", length = 100)
     protected String apodo;
 
     @Temporal(TemporalType.DATE)
     @Column(name = "FECHA_ALTA")
     protected Date fechaAlta;
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "TIPO_DE_PERSONA_ID")
     protected TipoPersona tipoDePersona;
 
 
 
 
     @Lob
     @Column(name = "OBSERVACIONES")
     protected String observaciones;
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "FORMA_ENVIO_ID")
     protected FormaEnvio formaEnvio;
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "FORMA_PAGO_ID")
     protected FormaPago formaPago;
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "PAIS_ID")
     protected Paises pais;
 
 
 
 
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "CUENTA_BANCARIA_DEFECTO_ID")
     protected CuentasBancarias cuentaBancariaDefecto;
 
     @Composition
     @OnDelete(DeletePolicy.CASCADE)
     @OneToMany(mappedBy = "tercero")
     protected List<CuentasBancarias> cuentasBancarias;
 
     @Column(name = "ENVIAR_DOCUMENTOS_EMAIL")
     protected Boolean enviarDocumentosEmail;
 
     @Column(name = "DIRECCION_WEB")
     protected String direccionWEB;
 
     @Column(name = "PGC_TERCERO", length = 10)
     protected String pgcTercero;
 
     @Column(name = "PGCAUX_TERCERO", length = 10)
     protected String pgcauxTercero;
 
     @Column(name = "RECARGO_EQUIVALENCIA")
     protected Boolean recargoEquivalencia=false;
 
     @Column(name = "IRPF")
     protected BigDecimal irpf;
 
     @Column(name = "PGC_IRPF", length = 10)
     protected String pgcIRPF;
 
     @Column(name = "PGCAUX_IRPF", length = 10)
     protected String pgcauxIRPF;
 
     @Composition
     @OnDelete(DeletePolicy.CASCADE)
     @OneToMany(mappedBy = "tercero")
     protected List<Direccion> direcciones;
 
     @Composition
     @OnDelete(DeletePolicy.CASCADE)
     @OneToMany(mappedBy = "tercero")
     protected List<Contactos> contactos;
 
     @Composition
     @OnDelete(DeletePolicy.CASCADE)
     @OneToMany(mappedBy = "tercero")
     protected List<Adjuntos> adjuntos;
 
     @OneToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "FOTO_ID")
     protected FileDescriptor foto;
 
     public void setCuentaBancariaDefecto(CuentasBancarias cuentaBancariaDefecto) {
         this.cuentaBancariaDefecto = cuentaBancariaDefecto;
     }
 
     public CuentasBancarias getCuentaBancariaDefecto() {
         return cuentaBancariaDefecto;
     }
 
 
     public void setCuentasBancarias(List<CuentasBancarias> cuentasBancarias) {
         this.cuentasBancarias = cuentasBancarias;
     }
 
     public List<CuentasBancarias> getCuentasBancarias() {
         return cuentasBancarias;
     }
 
 
     public void setIrpf(BigDecimal irpf) {
         this.irpf = irpf;
     }
 
     public BigDecimal getIrpf() {
         return irpf;
     }
 
 
     public void setPgcIRPF(String pgcIRPF) {
         this.pgcIRPF = pgcIRPF;
     }
 
     public String getPgcIRPF() {
         return pgcIRPF;
     }
 
     public void setPgcauxIRPF(String pgcauxIRPF) {
         this.pgcauxIRPF = pgcauxIRPF;
     }
 
     public String getPgcauxIRPF() {
         return pgcauxIRPF;
     }
 
 
     public void setPais(Paises pais) {
         this.pais = pais;
     }
 
     public Paises getPais() {
         return pais;
     }
 
 
 
 
 
     public void setDireccionWEB(String direccionWEB) {
         this.direccionWEB = direccionWEB;
     }
 
     public String getDireccionWEB() {
         return direccionWEB;
     }
 
 
 
 
 
     public void setFechaAlta(Date fechaAlta) {
         this.fechaAlta = fechaAlta;
     }
 
     public Date getFechaAlta() {
         return fechaAlta;
     }
 
 
     public void setEnviarDocumentosEmail(Boolean enviarDocumentosEmail) {
         this.enviarDocumentosEmail = enviarDocumentosEmail;
     }
 
     public Boolean getEnviarDocumentosEmail() {
         return enviarDocumentosEmail;
     }
 
     public void setPgcTercero(String pgcTercero) {
         this.pgcTercero = pgcTercero;
     }
 
    public String getPgcTercero() {
         return pgcTercero;
     }
 
     public void setPgcauxTercero(String pgcauxTercero) {
         this.pgcauxTercero = pgcauxTercero;
     }
 
     public String getPgcauxTercero() {
         return pgcauxTercero;
     }
 
 
     public void setFoto(FileDescriptor foto) {
         this.foto = foto;
     }
 
     public FileDescriptor getFoto() {
         return foto;
     }
 
 
     public void setApodo(String apodo) {
         this.apodo = apodo;
     }
 
     public String getApodo() {
         return apodo;
     }
 
 
     public void setAdjuntos(List<Adjuntos> adjuntos) {
         this.adjuntos = adjuntos;
     }
 
     public List<Adjuntos> getAdjuntos() {
         return adjuntos;
     }
 
 
     public void setRecargoEquivalencia(Boolean recargoEquivalencia) {
         this.recargoEquivalencia = recargoEquivalencia;
     }
 
     public Boolean getRecargoEquivalencia() {
         return recargoEquivalencia;
     }
 
 
     public void setContactos(List<Contactos> contactos) {
         this.contactos = contactos;
     }
 
     public List<Contactos> getContactos() {
         return contactos;
     }
 
 
     public void setDirecciones(List<Direccion> direcciones) {
         this.direcciones = direcciones;
     }
 
     public List<Direccion> getDirecciones() {
         return direcciones;
     }
 
 
    public void setFormaEnvio(FormaEnvio formaEnvio) {
         this.formaEnvio = formaEnvio;
     }
 
     public FormaEnvio getFormaEnvio() {
         return formaEnvio;
     }
 
     public void setFormaPago(FormaPago formaPago) {
         this.formaPago = formaPago;
     }
 
     public FormaPago getFormaPago() {
         return formaPago;
    }
 
 
 
 
     public void setObservaciones(String observaciones) {
         this.observaciones = observaciones;
     }
 
     public String getObservaciones() {
         return observaciones;
     }
 
 
     public void setNombre(String nombre) {
         this.nombre = nombre;
     }
 
     public String getNombre() {
         return nombre;
     }
 
 
     public void setTipoDePersona(TipoPersona tipoDePersona) {
         this.tipoDePersona = tipoDePersona;
     }
 
     public TipoPersona getTipoDePersona() {
         return tipoDePersona;
     }
 
 
 
 
     public void setCif(String cif) {
         this.cif = cif;
     }
 
     public String getCif() {
         return cif;
     }

     public void setRazonSocial(String razonSocial) {
         this.razonSocial = razonSocial;
     }
 
     public String getRazonSocial() {
        return razonSocial;
     }
 
 
 
 }

Proveedor:
 import javax.persistence.Entity;
 import javax.persistence.Table;
 import com.haulmont.cuba.core.entity.StandardEntity;
 import javax.persistence.DiscriminatorValue;
 import com.haulmont.chile.core.annotations.NamePattern;
 import javax.persistence.PrimaryKeyJoinColumn;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Column;
 import com.haulmont.cuba.core.entity.annotation.Listeners;
 import com.haulmont.chile.core.annotations.NumberFormat;
 
 @Listeners("myapp_ProveedorEntityListener")
 @PrimaryKeyJoinColumn(name = "ID", referencedColumnName = "ID")
 @Table(name = "MYAPP_PROVEEDOR")
 @NamePattern("%s-%s|codigoProveedor,nombre")
 @DiscriminatorValue("Proveedor")
 @Entity(name = "myapp$Proveedor")
 public class Proveedor extends Tercero {
     private static final long serialVersionUID = -1635446329009452675L;
 
     @NumberFormat(pattern = "#########0")
     @Column(name = "CODIGO_PROVEEDOR")
     protected Long codigoProveedor;
 
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "ALMACEN_DEFECTO_ID")
     protected Almacen almacenDefecto;
 
 
 
     public void setCodigoProveedor(Long codigoProveedor) {
         this.codigoProveedor = codigoProveedor;
     }
 
     public Long getCodigoProveedor() {
         return codigoProveedor;
     }
 
 
     public void setAlmacenDefecto(Almacen almacenDefecto) {
         this.almacenDefecto = almacenDefecto;
     }
 
     public Almacen getAlmacenDefecto() {
         return almacenDefecto;
     }
 
 
 }

I tried to reproduce your problem on a test project (attached) but it worked fine. If you can see the difference between the test project and your data model and use case, please let us know.

test-fts-namepattern.zip (84.3 KB)

Thanks for your answer. Some days ago, it worked also fine for me. It’s second time that occurs this issue, as said above, but previously it fixed by itself.

Took a look at you attached example and cant’ see a difference, but there are only 4 fields. I don’t think this is the matter.

So, if I can find a solution, will let you know.

I removed codigoProveedor from @NamePattern and it works. Nevertheless, results returns instances of Tercero, not of Proveedor, like your example. Should be the Proveedor entity. This explains why codigoProveedor is unfetched, because it’s not part of the result entity (Tercero). I figure out that something weird happens.

Could you check if both entities are registered in your fts.xml?

Yes, they are

-<entity class="com.company.myapp.entity.Proveedor">

<include re=".*"/>

</entity>


-<entity class="com.company.myapp.entity.Tercero">

<include re=".*"/>

</entity>


-

How did you come to this conclusion? The stack trace shows that the Proveedor entity is loaded:

java.lang.IllegalStateException: Cannot get unfetched attribute [codigoProveedor] from detached object com.company.myerp.entity.Proveedor-e642bc8e-d573-9c26-68a8-a2e35a309991 [detached].

Because i did a trace and saw all getters are from Tercero but codigoProveedor, and because when I removed codigoProveedor from @NamePattern, the returned entity is Tercero and trying to open a no existing Tercero edit screen.

Updated to 6.9.6
I have found that the problem persists. In fact, I have verified that it occurs in all the entities that inherit from another.
Reviewing the trace, I verified that the entity that the FTS selects is the child, but the getters that appears in the list of FTS “getters” in trace, are from the parent, Except those of the @NamePattern. Therefore, it seems that FTS finds the child entity, but it loads the parent’s, and when it tries to execute the getter of the @NamePattern (which belongs to the child) it gives an unfetched error because the loaded entity actually is the parent.

I know all this sounds very messy, but I’m fighting with this several days and can’t see what is wrong in my project.

Perhaps this information throughs a bit of light to find the issue.

P.D. Did a reindexall and a processentirequeue at JMX.

Found a solution wich works for me. Since Tercero is the Parent entity and has no sense to be shown for its own, but only for its childs (Proveedor, Cliente, etc), I removed Tercero from fts.xml file and now it works fine. Only links to entities for Proveedor, Cliente, etc are shown and no exception is thrown.

2 Likes