formFactory.form() doesn't exist ! PlayFramework - java

I've a little problem, i want to create a web app and i learn PlayFramework with java documentation of
This sample code :
public Result hello() {
DynamicForm requestData = formFactory.form().bindFromRequest();
String firstname = requestData.get("firstname");
String lastname = requestData.get("lastname");
return ok("Hello " + firstname + " " + lastname);
}
The ''formFactory'' doesn't exist.
http://i.imgur.com/W941Bgz.png
Why I don't have this field ?
And when i want to create a model, i don't have the model class
http://i.imgur.com/9FW7wp1.png
Thanks you so much if you resolve my problem ! :)

From the documentation:
To wrap a class you have to inject a play.data.FormFactory into your Controller
Play already knows about FormFactory, so just add a constructor parameter for it:
public class FooController {
private final FormFactory formFactory;
#Inject
public FooController(final FormFactory formFactory) {
this.formFactory = formFactory;
}
public Result hello() {
DynamicForm requestData = formFactory.form().bindFromRequest();
String firstname = requestData.get("firstname");
String lastname = requestData.get("lastname");
return ok("Hello " + firstname + " " + lastname);
}
}
I'm guessing the Model you mention is that of EBean. You need to enable EBean for your project, and then you'll have the necessary classes on your classpath.
In project/plugins.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")
build.sbt:
lazy val myProject = (project in file(".")).enablePlugins(PlayJava, PlayEbean)
More information is available in the relevant docs.

First make sure to import these 2 libaries in your Play Controller:
import javax.inject.Inject;
import play.data.FormFactory;
After that before using the Form Builder, inject it into your code:
#Inject FormFactory formFactory;
Your code should work fine after this.

You will have to inject your formFactory like this:
#Inject FormFactory formFactory;

Related

How to make saga starts

I'm trying to use Axon and Saga design pattern to send data between Micorservices using Java
I have two service one for Order and one for Product CQRS Design pattern works perfectly I mean I send data to axon and I see it in my dashboard and then by query data gets and save in read database (MySQL).
Today I tried to use Saga design pattern and when create a new order send ReserveProductCommand to axon and gets by Product service but saga doesn't event start and I don't know why
Below Saga class in Order service that should gets OrderCreatedEvent and Log the message but it doesn't
#Saga
public class OrderSaga {
private final transient CommandGateway commandGateway;
private static final Logger LOGGER = LoggerFactory.getLogger(OrderSaga.class);
#Autowired
public OrderSaga(CommandGateway commandGateway) {
this.commandGateway = commandGateway;
}
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
public void handle(OrderCreatedEvent orderCreatedEvent) {
ReserveProductCommand reserveProductCommand = ReserveProductCommand
.builder()
.orderId(orderCreatedEvent.getOrderId())
.productId(orderCreatedEvent.getProductId())
.quantity(orderCreatedEvent.getQuantity())
.userId(orderCreatedEvent.getUserId())
.build();
LOGGER.info("OrderCreatedEvent handled for orderId: " + reserveProductCommand.getOrderId() + " and productId: " + reserveProductCommand.getProductId());
commandGateway.send(reserveProductCommand, new CommandCallback<ReserveProductCommand, Object>() {
#Override
public void onResult(CommandMessage<? extends ReserveProductCommand> commandMessage, CommandResultMessage<?> commandResultMessage) {
if (commandResultMessage.isExceptional()){
}
}
});
}
#SagaEventHandler(associationProperty = "orderId")
public void handle(ProductReservedEvent productReservedEvent){
LOGGER.info("ProductReservedEvent is called for productId: " + productReservedEvent.getProductId() + " and orderId: " + productReservedEvent.getOrderId());
}
}
Below OrderCreatedEvent
#Data
#AllArgsConstructor
#NoArgsConstructor
public class OrderCreatedEvent {
public String orderId;
private String userId;
private String productId;
private int quantity;
private String addressId;
private OrderStatus orderStatus;
}
I've seen axon dashboard OrderCreatedEvent has been published there
I think the problem is that Axon requires a no-arg constructor on Saga's. You should use field injection for the resources. This passage in the reference guide explains it:
The SpringResourceInjector uses Spring's dependency injection mechanism to inject resources into a Saga. This means you can use setter injection or direct field injection if you require. The method or field to be injected needs to be annotated in order for Spring to recognize it as a dependency, for example with #Autowired.
The passage can be found here: https://docs.axoniq.io/reference-guide/axon-framework/sagas/implementation. Changing the constructor injection to field injection, like the following sample, should work for you:
#Saga
public class OrderSaga {
#Autowired
private final transient CommandGateway commandGateway;
private static final Logger LOGGER = LoggerFactory.getLogger(OrderSaga.class);
// Abbreviated for clarity
}

How do I test a Service with calls to an external API in Spring

Okay, so I am pretty new to testing and Spring Boot in general, so please correct me if I am doing something completely wrong here in the first place.
As a project my team and I are making a Web Application using Spring Boot where we are making calls to the Microsoft Graph API in some of our services. See this service for cancelling an event in a user's calendar:
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.models.extensions.IGraphServiceClient;
import com.microsoft.graph.requests.extensions.GraphServiceClient;
import org.springframework.stereotype.Service;
#Service
public class CancelEventService {
public void cancelEvent(final String token, final String id) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
IGraphServiceClient graphServiceClient = GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
graphServiceClient.me().events(id)
.buildRequest()
.delete();
}
}
This is working great, but I have been struggling for a couple of days with how to write unit tests for this. The way I see it, I want to either make mocks of the GraphServiceClient, or use a tool like WireMock to make the request go to a mockserver and return some values I configure.
I've tried doing both, but I can't make mocks of GraphServiceClient because it is not a Bean in my project, so I can't figure out how I should proceed to make an implementation I can autowire in to my Service.
When it comes to WireMock I am not even sure I understand if it is capable of doing what I want to, and if it is, I sure haven't been able to configure it correctly (note that we are using JUnit 5 for this project). A simple example where you make a GET-request to Google.com and return "Hello" via WireMock would suffice to get me going here.
Any concrete examples of what I should do, or even just a nod in the right direction would be well appreciated.
Well, I cannot assure you that it will work but it will give you a better landscape of the situation:
1) So first, we need to make a slight change on your service.
Need to extract IGraphServiceClient from the method so we can mock it later, see:
#Service
public class CancelEventService {
private IGraphServiceClient graphServiceClient;
#Autowired
public CancelEventService(IGraphServiceClient graphServiceClient){
this.graphServiceClient = graphServiceClient;
}
public void cancelEvent(final String token, final String id) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
graphServiceClient = GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
graphServiceClient.me().events(id)
.buildRequest()
.delete();
}
}
2) The test would look like this:
(Notice that all we are using here is included in spring boot test module, so you shouldn't need to add anything to the project dependencies)
#RunWith(SpringRunner.class)
public class CancelEventServiceTest {
private IGraphServiceClient graphServiceClientMock;
private CancelEventService serviceToBeTested;
#Before
public void setUp(){
graphServiceClientMock = Mockito.mock(IGraphServiceClient.class, RETURNS_DEEP_STUBS);
serviceToBeTested = new CancelEventService(graphServiceClientMock);
}
#Test
public void test_1() {
serviceToBeTested.cancelEvent("token", "id");
verify(graphServiceClientMock, times(1)).me().events("id").buildRequest()
.delete();
}
}
Hope it helps!
As a follow up on this, we found a solution to the problem by creating a class
GraphServiceClientImpl with a method that returns an instantiated GraphServiceClient.
#Component
public class GraphServiceClientImpl {
public IGraphServiceClient instantiateGraphServiceClient(final String token) {
IAuthenticationProvider authenticationProvider = iHttpRequest -> iHttpRequest.addHeader("Authorization", "Bearer " + token);
return GraphServiceClient.builder().authenticationProvider(authenticationProvider).buildClient();
}
}
#Service
public class CancelEventService{
private GraphServiceClientImpl graphServiceClientImpl;
public CancelEventService(final GraphServiceClientImpl graphServiceClientImpl) {
this.graphServiceClientImpl = graphServiceClientImpl;
}
public void cancelEvent(final String token, final String id) {
IGraphServiceClient graphServiceClient = graphServiceClientImpl.instantiateGraphServiceClient(token);
graphServiceClient
.me()
.events(id)
.buildRequest()
.delete();
}
}
Then, our test:
#ExtendWith(MockitoExtension.class)
class CancelEventServiceTest {
#Mock
private GraphServiceClientImpl graphServiceClientImpl;
#InjectMocks
private CancelEventService cancelEventService;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
void cancelEvent_Successful() {
//given
IGraphServiceClient serviceClientMock = mock(IGraphServiceClient.class, RETURNS_DEEP_STUBS);
given(graphServiceClientImpl.instantiateGraphServiceClient(anyString())).willReturn(serviceClientMock);
//when
cancelEventService.cancelBooking("Token", "1");
//then
verify(serviceClientMock, times(1)).me();
}
}
Probably not the optimal solution, but it works. Any other takes on this would be welcome!

How to get the functionality of #Autowired JpaRepository by its Class

In my spring boot application I have a class 'repo' that is found by its class name
Class<?> repo = Class.forName("com.example.demo.repository." + modelName + "Repository");
where the modelName is a String.
repo.toString() returns
interface com.example.demo.repository.LaptopRepository
I want to have an ability to use laptopRepository.findAll() methods.
I exactly don't know which modelName I will have.
So I could not use #Autowired annotation outside the method.
Instead I want to use laptopRepository inside the method, which takes the modelName attribute.
#GetMapping("/administration")
public String getModelInstances(#RequestParam("modelName")String modelName, Model model) throws ClassNotFoundException {
Class<?> repo = Class.forName("com.example.demo.repository." + modelName + "Repository");
// #Autowired
// repo repoRepository;
model.addAttribute("objects", repoRepositories.findAll());
return "administration";
}
Just use Sping application context to get desired repository bean by its type.
1) Autowire context in your controller
#Autowired
private ApplicationContext appContext;
2) Use it in your method
appContext.getBean(Class.forName("com.example.demo.repository." + modelName + "Repository"));

Spring Boot Application Error Page

I'm starting to learn Spring Boot, and I'm following a tutorial on youtube. However, there is an weird thing happening on my project. I just created a Controller called GreetingController. Below is the complete code of the class
#RestController
#EnableAutoConfiguration
public class GreetingController {
private static BigInteger nextId;
private static Map<BigInteger, Greeting> greetingMap;
private static Greeting save(Greeting greeting) {
if (greetingMap == null) {
greetingMap = new HashMap<BigInteger, Greeting>();
nextId = BigInteger.ONE;
}
greeting.setId(nextId);
nextId = nextId.add(BigInteger.ONE);
greetingMap.put(greeting.getId(), greeting);
return greeting;
}
static {
Greeting g1 = new Greeting();
g1.setText("Hello World");
save(g1);
Greeting g2 = new Greeting();
g2.setText("Hola Mundo");
save(g2);
}
#RequestMapping(value = "/api/greetings", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Greeting>> getGreetings() {
Collection<Greeting> greetings = greetingMap.values();
return new ResponseEntity<Collection<Greeting>>(greetings,
HttpStatus.OK);
}
}
The controller is under the following package:
However, when I bootstrap the application with the URL http://localhost:8080/api/greetings the following error appears on my page:
But, when I put the GreetingController in the same package of Application class, as the image below:
And then get the same URL http://localhost:8080/api/greetings, I got the right response:
Can anyone explain me why?
Rename your com.example package to org.example. Spring boot scans for controllers all subpackages of package of class when you place your #SpringBootApplication annotation.
Or put #ComponentScan("org.example") on the same class. This way you tell spring boot where to search your controllers (and other beans).
If you want to support having a controller in another package, you need to include it in the component scan of your Application.
In Application.java, you could add the following:
#ComponentScan({com.example, org.example})
By default, the package that Application is in will be included in the ComponentScan, which is why it was working for you when you had the controller in the same package as Application.
Also, you don't need the #EnableAutoConfiguration annotation on your controller, FYI.

Spring RestTemplate custom mapping

I'm new to Spring and following along the example at http://spring.io/guides/gs/consuming-rest.
I noticed they haven't mapped all the JSON elements from http://graph.facebook.com/pivotalsoftware so I wanted to extend the example a little. For this example, I wanted to add "likes" and "were_here_count", like so in Page.java:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown = true)
public class Page {
private String name;
private String about;
private String phone;
private String website;
private int were_here_count;
private int likes;
public String getName() {return name;}
public String getAbout() {return about;}
public String getPhone() {return phone;}
public String getWebsite() {return website;}
public int getVisitCount() {return were_here_count;}
public int getLikes() {return likes;}
}
and making these changes in Application.java:
import org.springframework.web.client.RestTemplate;
public class Application {
public static void main(String args[]) {
RestTemplate restTemplate = new RestTemplate();
Page page = restTemplate.getForObject("http://graph.facebook.com/pivotalsoftware", Page.class);
System.out.println("Name: " + page.getName());
System.out.println("About: " + page.getAbout());
System.out.println("Phone: " + page.getPhone());
System.out.println("Website: " + page.getWebsite());
System.out.println("Visit count: " + page.getVisitCount());
System.out.println("Likes: " + page.getLikes());
}
}
I was thinking that the mapping was done by element name, and that worked for "likes", but didn't for "were_here_count". Output:
Name: Pivotal
About: Pivotal is enabling the creation of modern software applications that leverage big & fast data – on a single, cloud independent platform.
Phone: (650) 286-8012
Website: http://www.pivotal.io
Visit count: 0
Likes: 1175
were_here_count is currently at 60. I'm guessing the default converter didn't like the underscore in the variable name. So I used the overloaded version of getForObject, providing my own mapping, like so:
package hello;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.client.RestTemplate;
public class Application {
public static void main(String args[]) {
RestTemplate restTemplate = new RestTemplate();
Map<String, String> variables = new HashMap<String, String>(3);
variables.put("name", "name");
variables.put("about", "about");
variables.put("phone", "phone");
variables.put("website", "website");
variables.put("were_here_count", "were_here_count");
variables.put("likes", "likes");
Page page = restTemplate.getForObject("http://graph.facebook.com/pivotalsoftware", Page.class, variables);
System.out.println("Name: " + page.getName());
System.out.println("About: " + page.getAbout());
System.out.println("Phone: " + page.getPhone());
System.out.println("Website: " + page.getWebsite());
System.out.println("Visit count: " + page.getVisitCount());
System.out.println("Likes: " + page.getLikes());
}
}
But all to no avail. I've seen a few examples regarding custom JSON converters here but didn't understand them well - plus, this is a much simpler example, could I not get this done with a simple String-String mapping of variable names?
Anyone know how to do this and willing to show me how to build a custom converter and what the necessary steps are? Thank you! :)
Try adding some of Jackson's annotations to your Page class to help with the deserialization of the JSON. You should be able to tell Jackson (which will handle serialization/deserialization of JSON in Spring by default), what attributes in the response JSON map to your POJO attributes.:
public class Page {
...
#JsonProperty("were_here_count")
private int wereHereCount;
...
}
Another option, if you are not sure what attributes are being returned, is to just map the JSON to a Map:
Map<String,Object> map = restTemplate.getForObject("http://graph.facebook.com/pivotalsoftware", Map.class);
for (Map.Entry entry: response.entrySet()){
// do stuff...
}
Sometime this is the easier way to do custom object mapping when the response JSON is convoluted or just doesn't deserialize easily.
What does your setter for Page looks like? It works for me with this setter:
public void setWere_here_count(int were_here_count) {
this.were_here_count = were_here_count;
}

Categories