当前位置: 首页 > 知识库问答 >
问题:

使用MapStruct转换时的循环引用。溢出错误。上下文不起作用

苗冯浩
2023-03-14

我有2个实体,1对1的关联(ProfileEntity和VCardEntity)

实体vcard:

@Entity
@Table(name = "vcard")
@AllArgsConstructor
@NoArgsConstructor
@Data
@SequenceGenerator(name="vcard_id_seq_generator", sequenceName="vcard_id_seq", allocationSize = 1)
public class VCardEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "vcard_id_seq_generator")
    @Column(name="vcard_id")
    Long id;
    String account;
    @Column(name = "first_name")
    String firstName;
    @Column(name = "last_name")
    String lastName;
    @Column(name = "pbxinfo_json")
    String pbxInfoJson;
    @Column(name = "avatar_id")
    String avatarId;
    @OneToOne(mappedBy = "vcard")
    ProfileEntity profile;
}

实体简介:

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Table(name = "profile")
public class ProfileEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "profile_id")
    private Long profileId;

    private String account;
    @Column(name = "product_id")
    private String productId;
    
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "vcard_id", referencedColumnName = "vcard_id")
    private VCardEntity vcard;
}

我使用map struct如下:

public class CycleAvoidingMappingContext {
    private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();

    @BeforeMapping
    public <T> T getMappedInstance(Object source, @TargetType Class<T> targetType) {
        return targetType.cast(knownInstances.get(source));
    }
    
    @BeforeMapping
    public void storeMappedInstance(Object source, @MappingTarget Object target) {
        knownInstances.put( source, target );
    }
}

@Mapper(componentModel = "spring")
public interface EntityToProfile {
    ProfileEntity profileToEntity(Profile profile, @Context CycleAvoidingMappingContext context);
    Profile entityToProfile(ProfileEntity entity, @Context CycleAvoidingMappingContext context);
}

@Mapper(componentModel = "spring")
public interface EntityToVCard {
    VCard entityToVcard(VCardEntity entity, @Context CycleAvoidingMappingContext context);
    VCardEntity vcardToEntity(VCard vcard, @Context CycleAvoidingMappingContext context);
}

最后,我在我的服务中调用映射:

@Service
@RequiredArgsConstructor
@Slf4j
public class DefaultChatService implements ChatService {
    private final ProfileRepository profileRepository;
    private final EntityToProfile entityToProfileMapper;
    private final EntityToVCard entityToVCardMapper;

    @Override
    public List<Profile> findAllProfile(Optional<Long> id) {
        if (id.isPresent()) {
            Optional<ProfileEntity> result = profileRepository.findById(id.get());
            if (result.isPresent()) {
                Profile profile = entityToProfileMapper.entityToProfile(result.get(), new CycleAvoidingMappingContext());
                return Stream.of(profile).collect(Collectors.toList());
            }
        }
        return new ArrayList<Profile>();
    }
}

我得到了错误ERROR 15976---[nio-8080-exec-1]o. a. c. c.C.[.[.]Servlet.service()的servlet[调度Servlet]在上下文与路径[]抛出异常[处理程序调度失败;嵌套异常是java.lang.StackOverflow错误]与根本原因java.lang.StackOverflow错误:空

有什么想法吗?我该怎么解决?在我看来,我做了这里所写的一切,在使用MapStruct转换时防止循环引用,但它不适合我

共有1个答案

郭琦
2023-03-14

找到了一个解决方案,我所要做的就是为我的模型从@Value改为@Data

给出的例子:

@Data
public class Profile {
    Long profileId;
    String account;
    String productId;
    VCard vcard;
}

@Data
public class VCard {
    Long id;
    String account;
    String firstName;
    String lastName;
    String pbxInfoJson;
    String avatarId;
    Profile profile;
}

否则mapstruct无法生成正确的映射代码。它试图在创建一个对象(例如Profile)后将一个实例存储在已知实例中。但是因为@value没有提供在创建对象(不可变对象)后设置属性的方法,所以它必须先创建所有设置,然后使用所有参数构造函数,这首先导致映射配置文件,反过来又试图做同样的事情,首先映射vCard在将VCard对象存储在已知实例中之前。这就是循环引用问题无法解决的原因

正确生成的代码

public Profile entityToProfile(ProfileEntity entity, CycleAvoidingMappingContext context) {
        Profile target = context.getMappedInstance( entity, Profile.class );
        if ( target != null ) {
            return target;
        }

        if ( entity == null ) {
            return null;
        }

        Profile profile = new Profile();

        context.storeMappedInstance( entity, profile );

        profile.setAccount( entity.getAccount() );
        profile.setProductId( entity.getProductId() );
        profile.setDeviceListJson( entity.getDeviceListJson() );
        profile.setLastSid( entity.getLastSid() );
        profile.setBalanceValue( entity.getBalanceValue() );
        profile.setBalanceCurrency( entity.getBalanceCurrency() );
        profile.setStatusJson( entity.getStatusJson() );
        profile.setData( entity.getData() );
        profile.setMissedCallsCount( entity.getMissedCallsCount() );
        profile.setFirstCallSid( entity.getFirstCallSid() );
        profile.setLastMissedCallSid( entity.getLastMissedCallSid() );
        profile.setRemoveToCallSid( entity.getRemoveToCallSid() );
        profile.setOutgoingLines( entity.getOutgoingLines() );
        profile.setFeatures( entity.getFeatures() );
        profile.setPermissions( entity.getPermissions() );
        profile.setVcard( vCardEntityToVCard( entity.getVcard(), context ) );

        return profile;
    }
}

如您所见,首先,它将对象保存在上下文中。StoreMappeInstance(实体、配置文件);然后填充属性。

 类似资料:
  • 问题内容: .flex-container { 当我删除flex属性时,它工作正常。 我想知道为什么柔韧性会影响省略号。 TIA 问题答案: 您的问题在于缺少“灵活的孩子”。这些将需要包含样式以截断元素,而不是父容器。 尝试将truncate属性移动到一个单独的类,如下所示:

  • 今天,我开始使用MapSTRt为我的项目创建我的模型到DTO转换器,我想知道它是否自动处理循环引用,但事实证明它没有。 这是我用来测试它的转换器: 这就是测试: Notifica、AvvisionNotifica及其各自的模型都是带有setter和getter的简单POJO,因此我认为无需发布代码(如果您想知道,Notifica扩展了Corrispondenza) 这段代码进入了一个无限的循环,这

  • 我的for-each循环中出现了这个错误:

  • 我有一个多边形的数据帧,并希望循环,以便创建一个新的列检查,如果一个特定的点在一个或多个多边形(因为它们不是排他性的)。我试图遵循geopandas的教程,但这似乎不起作用,因为所有的列都返回一个“假”。有人能指出我做错了什么吗?非常感谢。以防万一,文件quartier_paris.geojson是一个经典的Geojson文件,它是读没有问题(形状出现,我可以去所有quartiers.explor

  • 昨天我检查了一个突出的产品幻灯片,我在一个网页的首页是不是属性垂直对齐只在火狐,它在IE和Chrome工作正常。 我在搜索信息,很多年前我在FF上发现了很多bug。我尝试了一些我找到的解决方案,但没有一个有效。 在chrome和IE上,div位于窗口的中心,而在firefox中,该功能会向右对齐,使窗口大于100%。 幻灯片基于:http://wordpress.org/extend/plugin

  • 我试图从Selenium驱动ChromeDriver启动的google-chrome浏览上下文中检索的值。 使用google-chrome-devtools,我可以检索和,如下所示: 但是使用Selenium的方法,我可以提取,但是会引发以下循环引用错误: > 代码块: 控制台输出: 我已经通过了以下关于循环引用的讨论,我理解了这个概念。但我不知道我应该如何在这里解决这个问题。 null