带有 Spring 消息传递和 GsonMessageConverter 的 LazyInitializationException
LazyInitializationException with Spring Messaging and GsonMessageConverter
我正在使用 Spring Boot
与 Spring Messaging
和 Gson
进行 websocket 连接并向客户端发送消息。现在我在向我的模型添加新字段并将其发送给客户端后遇到 LazyInitializationException
错误。
这是我的模型 class:
@Entity
public class Vehicle {
@Expose
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Expose
private String name;
//...
//some other simple fields
//...
@Expose
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "vehicle_property_values", joinColumns = @JoinColumn(name = "vehicle_id"))
@MapKeyColumn(name = "key")
@Column(name="value")
private Map<String, String> properties = new HashMap<>();
}
我正在使用 GsonMessageConverter
将对象转换为 json 并从 https://github.com/Coding/WebIDE-Backend/blob/master/src/main/java/net/coding/ide/web/message/GsonMessageConverter.java
发送给客户端
Converter 工作正常,但最近我已将 Map<String, String> properties
添加到我的 Vehicle
模型,但出现问题。我遇到异常:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.vehicles.model.Vehicle.properties, could not initialize proxy - no Session
第 105 行 GsonMessageConverter
this.gson.toJson(payload, writer);
这是我在服务中发送消息的方式 class:
@Service
@Transactional
class VehicleServiceImpl implements VehicleService {
@Autowired
VehicleRepository vehicleRepository; //JpaRepository
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
private final ConcurrentLinkedDeque<Vehicle> pendingVehicles = new ConcurrentLinkedDeque<>();
//..some other fields and methods irrelevant in this case
//method called from controller
@Override
void addPendingVehicle(Vehicle vehicle) {
//set some variables in vehicle
vehicle = vehicleRepository.save(vehicle);
pendingVehicles.add(vehicle);
}
@Scheduled(initialDelay = 60000, fixedRate = 60000)
@Transactional
void sendPendingVehicles() {
if(pendingVehicles.size() > 0) {
simpMessagingTemplate.convertAndSend("/topic/vehicles", pendingVehicles);
pendingVehicles.clear();
}
}
}
这是我的 WebSocket 配置(只有非空方法):
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/testapp").setAllowedOrigins("*").withSockJS();
}
@Override
public boolean configureMessageConverters(List<MessageConverter> converters) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
converters.add(new GsonMessageConverter().setGson(gson));
return true;
}
}
我不知道如何修复它。如何使其成为事务性的?
我不需要 properties
在 websocket 消息中发送,所以我创建了注释
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcludeWebSocketSerialization { }
并将 ExclusionStrategy
添加到我的 Gson
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
我正在使用 Spring Boot
与 Spring Messaging
和 Gson
进行 websocket 连接并向客户端发送消息。现在我在向我的模型添加新字段并将其发送给客户端后遇到 LazyInitializationException
错误。
这是我的模型 class:
@Entity
public class Vehicle {
@Expose
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Expose
private String name;
//...
//some other simple fields
//...
@Expose
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "vehicle_property_values", joinColumns = @JoinColumn(name = "vehicle_id"))
@MapKeyColumn(name = "key")
@Column(name="value")
private Map<String, String> properties = new HashMap<>();
}
我正在使用 GsonMessageConverter
将对象转换为 json 并从 https://github.com/Coding/WebIDE-Backend/blob/master/src/main/java/net/coding/ide/web/message/GsonMessageConverter.java
Converter 工作正常,但最近我已将 Map<String, String> properties
添加到我的 Vehicle
模型,但出现问题。我遇到异常:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.vehicles.model.Vehicle.properties, could not initialize proxy - no Session
第 105 行 GsonMessageConverter
this.gson.toJson(payload, writer);
这是我在服务中发送消息的方式 class:
@Service
@Transactional
class VehicleServiceImpl implements VehicleService {
@Autowired
VehicleRepository vehicleRepository; //JpaRepository
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
private final ConcurrentLinkedDeque<Vehicle> pendingVehicles = new ConcurrentLinkedDeque<>();
//..some other fields and methods irrelevant in this case
//method called from controller
@Override
void addPendingVehicle(Vehicle vehicle) {
//set some variables in vehicle
vehicle = vehicleRepository.save(vehicle);
pendingVehicles.add(vehicle);
}
@Scheduled(initialDelay = 60000, fixedRate = 60000)
@Transactional
void sendPendingVehicles() {
if(pendingVehicles.size() > 0) {
simpMessagingTemplate.convertAndSend("/topic/vehicles", pendingVehicles);
pendingVehicles.clear();
}
}
}
这是我的 WebSocket 配置(只有非空方法):
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/testapp").setAllowedOrigins("*").withSockJS();
}
@Override
public boolean configureMessageConverters(List<MessageConverter> converters) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
converters.add(new GsonMessageConverter().setGson(gson));
return true;
}
}
我不知道如何修复它。如何使其成为事务性的?
我不需要 properties
在 websocket 消息中发送,所以我创建了注释
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcludeWebSocketSerialization { }
并将 ExclusionStrategy
添加到我的 Gson
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getAnnotation(ExcludeWebSocketSerialization.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})