My method in my rest controller keeps looping.
The method is supposed to get a project from the Mongo database then call another API to get some data and save it again in mongo. It works but it just keeps looping
I use retrofit for my API calls and the application uses spring boot
This is the method that keeps looping
If you need something else just ask me
#RequestMapping(value = "/projects/{id}",method = RequestMethod.PUT)
public void updateCampaign(#PathVariable String id) throws IOException {
Project p = projectRepository.findProjectById(id);
Call<ResponseIndie> get = service.getAllFromCampaign(p.getIndiegogoCampaignId(),API_KEY);
ResponseIndie responseIndie =get.execute().body();
IndiegogoCampaign campaign = responseIndie.getIndiegogoCampaign();
p.setIndiegogoCampaignId(campaign.getId());
p.setIndiegogoCampaign(campaign);
projectRepository.save(p);
logger.info("project saved");
}
Related
I'm coding a game, when a player end its turn, I want to notify the opponent that it's his turn to play.
So I'm storing WebSocketSessions in "Player" classes, so I just need to get an instance of a player to have access to his websocketsession.
The problem is that nothing is happening when I use the "send" method of a websocketsession stored in a "player" instance.
Here is my code to store a WebSocketSession in a player object, it actually receive properly messages from front end, and it is able to send a message back and it works:
#Component("ReactiveWebSocketHandler")
public class ReactiveWebSocketHandler implements WebSocketHandler {
#Autowired
private AuthenticationService authenticationService;
#Override
public Mono<Void> handle(WebSocketSession webSocketSession) {
Flux<WebSocketMessage> output = webSocketSession.receive()
.map(msg -> {
String payloadAsText = msg.getPayloadAsText();
Account account = authenticationService.getAccountByToken(payloadAsText);
Games.getInstance().getGames().get(account.getIdCurrentGame()).getPlayerById(account.getId()).setSession(webSocketSession);
return "WebSocketSession id: " + webSocketSession.getId();
})
.map(webSocketSession::textMessage);
return webSocketSession
.send(output);
}
}
And here is the code I use to notify the opponent player that it is its turn to play, the "opponentSession.send" method seems to produce no result, there is no error message, and it looks like I receive nothing on the front end. The sessions has the same ID than in the handle method so I think the session object is good, also the websocket session was opened and ready when I did my tests:
#RequestMapping(value = "/game/endTurn", method = RequestMethod.POST)
GameBean endTurn(
#RequestHeader(value = "token", required = true) String token) {
ObjectMapper mapper = new ObjectMapper();
Account account = authenticationService.getAccountByToken(token);
gameService.endTurn(account);
Game game = gameService.getGameByAccount(account);
//GameBean opponentGameBean = game.getOpponentGameState(account.getId());
//WebSocketMessage webSocketMessage = opponentSession.textMessage(mapper.writeValueAsString(opponentGameBean));
WebSocketSession opponentSession = game.getPlayerById(game.getOpponentId(account.getId())).getSession();
WebSocketMessage webSocketMessage = opponentSession.textMessage("test message");
opponentSession.send(Mono.just(webSocketMessage));
return gameService.getGameStateByAccount(account);
}
}
You can see on the screenshot that the handle method is working correctly, I'm able to send and receive message.
Websocket input and output
Does someone know how can I make the opponentSession.send method works correctly so that I can receive messages on the front end?
You are using the reactive stack for your websocket and WebSocketSession#send return a Mono<Void> but you don't subscribe to this Mono (you just assembled it) so nothing will happen until something subscribe to it.
In your endpoint it doesn't look like you are using webflux so you are in synchronous world so you don't have other choice than to block
opponentSession.send(Mono.just(webSocketMessage)).block();
If you are using webflux then you should change your method to return a Mono and do something like:
return opponentSession.send(Mono.just(webSocketMessage)).then(gameService.getGameStateByAccount(account));
If you are not familiar with this you should look into projectreactor and WebFlux
Hey I am having a POJO Class, after some code execution it contain result to be sent as Response from sprint controller.
PojoClass {
List<String> list = new ArrayList<String>();
// other variable
}
#RequestMapping(value="/someUrl", method=RequestMethod.GET)
public PojoClass getResult(#RequestParam(PRRQConstants.BUG_ID) String
bugId,HttpServletRequest request) throws Exception
{
// call service
// processing in service
return PojoClass;
}
Everything works fine if the size of list is small. But if it contain more than 2 million or a million elements, also after processing everything it stuck in sending Response back from controller to client.
Why this is happening ?
I have implemented by project using Spring-Data-Rest. I am trying to do an update on an existing record in a table. But when I try to send only a few fields instead of all the fields(present in Entity class) through my request, Spring-Data-Rest thinking I am sending null/empty values. Finally when I go and see the database the fields which I am not sending through my request are overridden with null/empty values. So my understanding is that even though I am not sending these values, spring data rest sees them in the Entity class and sending these values as null/empty. My question here is, is there a way to disable the fields when doing UPDATE that I am not sending through the request. Appreciate you are any help.
Update: I was using PUT method. After reading the comments, I changed it to PATCH and its working perfectly now. Appreciate all the help
Before update, load object from database, using jpa method findById return object call target.
Then copy all fields that not null/empty from object-want-to-update to target, finally save the target object.
This is code example:
public void update(Object objectWantToUpdate) {
Object target = repository.findById(objectWantToUpdate.getId());
copyNonNullProperties(objectWantToUpdate, target);
repository.save(target);
}
public void copyNonNullProperties(Object source, Object target) {
BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
}
public String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] propDesList = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(PropertyDescriptor propDesc : propDesList) {
Object srcValue = src.getPropertyValue(propDesc.getName());
if (srcValue == null) {
emptyNames.add(propDesc.getName());
}
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
You can write custom update query which updates only particular fields:
#Override
public void saveManager(Manager manager) {
Query query = sessionFactory.getCurrentSession().createQuery("update Manager set username = :username, password = :password where id = :id");
query.setParameter("username", manager.getUsername());
query.setParameter("password", manager.getPassword());
query.setParameter("id", manager.getId());
query.executeUpdate();
}
As some of the comments pointed out using PATCH instead of PUT resolved the issue. Appreciate all the inputs. The following is from Spring Data Rest Documentation:
"The PUT method replaces the state of the target resource with the supplied request body.
The PATCH method is similar to the PUT method but partially updates the resources state."
https://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.hiding-repository-crud-methods
Also, I like #Tran Quoc Vu answer but not implementing it for now since I dont have to use custom controller. If there is some logic(ex: validation) involved when updating the entity, I am in favor of using the custom controller.
I'm trying to write a JUnit test for my Spring module, after seeing that my logic is working using SwaggerUI.
What happens, however, is that I miss some data in my H2 instance (used for the tests only), and I don't understand why.
This is what I'm doing:
MyObjectController.java
#PostMapping("/myobject")
public void save(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Save and get id
Integer id = service.save();
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
// Run async
service.run(id); // At this stage, id = 1 because the insert completed correctly
// Return id
response.setHeader(HttpHeaders.LOCATION, location.toString());
}
MyObjectService.java
#Async
#Transactional
public void run(Integer id) throws Exception { // As above, id = 1 but this time data is not there!
// Retrieve and run
Optional<MyObject> myObject = myObjectDao.findById(id);
if (!myObject.isPresent()) {
throw new NotFound();
}
...
}
/myobject endpoint is called using MockMVC, and once called it correctly returns the expected id.
If I place a breakpoint at the beginning of service.run(Integer id), and I call /myobject using SwaggerUI, I can see that everything is fine, but this doesn't happen when running in JUnit.
Can you guys please help me with that?
I am very new to Spring MVC and AngularJS. The application basically does sync between selected tables from the two db instances. When sync is called the following service is called at the server end as below:
#RequestMapping(value = "configversion/{srcConfVersionId}/sync", method = RequestMethod.POST)
#ModelAttribute(DEFAULT_MODEL_ATTR_NAME)
#ResponseBody
public CustomResponse syncConfigurations(#PathVariable Long srcConfVersionId, #RequestBody SyncDTO dto) {
Date processingTime = new Date();
dto.setSrcConfVersionId(srcConfVersionId);
DeferredResult<Object> deferredResult = new DeferredResult<>();
SyncProcessingTask task = new SyncProcessingTask( dataSyncService, deferredResult, srcConfVersionId, dto);
Timer timer = new Timer();
timer.schedule(task, processingTime);
return new CustomResponse(deferredResult);
}
As far as i know the DeferredResult is used for async process where the result can be read in future.
From the front end side once the sync button is clicked it goes to new page which lists the results of sync. As the server continues in background the client shows the "In Progess" status. Now the question is how can i check the DeferredResult is changed from the AngularJS side?
You need to use the callback methods of DeferredResult. Implement the following.
DeferredResult.onCompletion(Runnable callback);