I'm using Spring Boot
with Spring Messaging
and Gson
for websocket connection and sending messages to client. Now I'm facing LazyInitializationException
error after adding new field to my model and sending it to client.
Here's my model 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<>();
}
I'm using GsonMessageConverter
to convert object to json and send to client from https://github.com/Coding/WebIDE-Backend/blob/master/src/main/java/net/coding/ide/web/message/GsonMessageConverter.java
Converter is working fine but recenlty I've added Map<String, String> properties
to my Vehicle
model and there's a problem. I'm getting exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.vehicles.model.Vehicle.properties, could not initialize proxy - no Session
in line 105 on the GsonMessageConverter
this.gson.toJson(payload, writer);
Here's how I send messages in my Service 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();
}
}
}
Here's my WebSocket configuration (only not empty methods):
@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;
}
}
I have no idea how to fix it. How to make it Transactional?
I didn't need to
properties
be send in websocket messages so I created annotationAnd added
ExclusionStrategy
to myGson