I have the Feature class as follows:
public class Feature {
private FeatureType featureType;
private Integer featureNumber;
#JsonProperty("isActive")
private boolean isActive;
#JsonProperty("isAutomatedFeature")
private boolean isAutomatedFeature;
private Feature() {
}
public FeatureType getFeatureType() {
return featureType;
}
public Integer getFeatureNumber() {
return featureNumber;
}
#JsonProperty("isActive")
public boolean isActive() {
return isActive;
}
#JsonProperty("isAutomatedFeature")
public boolean isAutomatedFeature() {
return isAutomatedFeature;
}
public static class Builder {
Feature feature=null;
public Builder() {
feature=new Feature();
}
public Builder setFeatureType(FeatureType featureType) {
feature.featureType=featureType;
return this;
}
public Builder setFeatureNumber(Integer featureNumber) {
feature.featureNumber=featureNumber;
return this;
}
#JsonProperty("isActive")
public Builder setIsActive(boolean isActive) {
feature.isActive=isActive;
return this;
}
#JsonProperty("isAutomatedFeature")
public Builder setIsCarryForwardAllowed(boolean isAutomatedFeature) {
feature.isAutomatedFeature=isAutomatedFeature;
return this;
}
public Feature build() {
return feature;
}
}
Now to create a feature we have an api called
api/v1/feature---POST and its payload will look like below:
"feature":{
"featureType":"XYZ",
"featureType":"40",
"isActive" :true,
"isAutomatedFeature" :true
}
But we can't call this api directly to create a feature so we use RestAssured RequestSpecificationImpl to hit the above API.
It will be something like this
public Response create(Feature feature) {
return post("api/v1/feature",feature);
}
Internally it creates the payload/body for the url and hit the api.So to hit the above method create we need the feature object which I created using builder.
Feature feature=new Feature.Builder().setFeatureType("XYZ").setFeatureNumber(40).setIsActive(true).setIsCarryForwardAllowed(true).build();
I expected the payload to be like above mentioned payload.
But the generated payload is something like this:
"feature":{
"featureType":"XYZ",
"featureType":"40",
"Active" :true,
"AutomatedFeature" :true
}
i.e it removes "is" from "isActive" and "isAutomatedFeature" and make them "Active" and "AutomatedFeature" respectively even when I am using #JsonProperty,so the api fails.
Can anyone guide me what I am doing wrong or how it can be resolved.
Thanks in advance.
Related
Please note: I am using Spring Boot here, not Spring MVC.
Java 8 and Spring Boot/Jackson here. I have the following enum:
public enum OrderType {
PARTIAL("partialOrder"),
FULL("fullOrder");
private String label;
OrderType(String label) { this.label = label; }
}
I would like to expose a POST endpoint where the client can place the OrderType#label as a request parameter, and Spring will know to convert the provided label into an OrderType like so:
#PostMapping("/v1/myapp/orders")
public ResponseEntity<?> acceptOrder(#RequestParam(value = "orderType") OrderType orderType) {
// ...
}
And hence the client could make a call such as POST /v1/myapp/orders?orderType=fullOrder and on the server, the controller would receive an OrderType instance.
How can I accomplish this?
This was so easy, a cave man could even do it.
Enum:
public class MyEnum {
FIZZ("sumpin"),
BUZZ("sumpinElse");
#JsonValue
private String label;
MyEnum(String label) { this.label = label; }
public String getLabel() { return this.label; }
public static Optional<MyEnum> toMyEnum(String label) {
if (label == null) {
return Optional.empty();
}
for (MyEnum mine : MyEnum.values()) {
if (label.equals(mine.getLabel()) {
return Optional.of(mine);
}
}
throw new IllegalArgumentException("no supported");
}
}
Spring converter:
public class MyEnumConverter implements Converter<String,MyEnum> {
#Override
public MyEnum convert(String label) {
Optional<MyEnum> maybeMine = MyEnum.toMyEnum(label);
if (maybeMine.isPresent()) {
return maybeMine.get():
}
// else, you figure out what you want your app to do,
// thats not my job!
}
}
Register it:
#Configuration
public class YourAppConfig {
#Autowired
public void configureConverter(FormatterRegistry registry) {
registry.addConverter(new MyEnumConverter());
}
}
Support it from inside in a controller/resource:
#Post("/v1/foobar/doSomething")
public ResponseEntity<?> doSomething(#RequestParam(value = "mine") MyEnum mine) {
// ... whatever
}
Use the darn thing in an API call:
POST http://yourlousyapp.example.com/v1/foobar/doSomething?mine=sumpin
It should be pretty easy but obviously I am lacking of basic knowlege.
I have a service which is ment to create ticket in BugTracking systems.
Creating plugins is pretty stright forward. there is an interface
public interface BugTracker {
boolean createAndSendIssue(Issue issue);
boolean updateAndSendIssue(Issue issue);
boolean closeIssue(Issue issue);
}
and API client for JIRA:
#Component
public class JiraClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using JIRA REST API
return false;
}
}
API CLient for Bugzilla:
#Component
public class BugzillaClient implements BugTracker {
#Override
public boolean createAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean updateAndSendIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
#Override
public boolean closeIssue(Issue issue) {
//Logic for using BUGZILLA REST API
return false;
}
}
Problem occurs on the Service which is handling MVC. Piece of it looks like:
#Service
public class BugTrackerService {
private final BugzillaClient bugzillaClient;
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
#Autowired
BugTrackerService(BugzillaClient bugzillaClient, JiraClient jiraClient) {
this.bugzillaClient = bugzillaClient;
this.jiraClient = jiraClient;
}
boolean processIssueTicketRequest(Issue issue){
if ( issue.getBugTrackerType().bugTrackingSystemType.name.equals(JIRA_TYPE)) {
return jiraClient.createAndSendIssue(issue);
} else if (issue.getBugTrackerType().bugTrackingSystemType.name.equals(BUGZILLA_TYPE)){
return bugzillaClient.createAndSendIssue(issue);
} else {
return false;
}
}
}
is it somehow possible to create method BugTrackerService.processIssueTicketRequest without all clients autowired? At this moment it is not so much of a problem but after integrating with more and more systems this service will become complex.
Depending on how reusable you want implementations to be, I'd probably put the logic of checking whether the given issue is of matching typing into the interface, eg
boolean canWorkWithGivenIssue(Issue issue);
With that in place then you don't need to know actual types of trackers you dispatch on, and merely aggregate them into the list. Spring will do that for you if you annotate a collection with #Autowired, in which cases it will provide you all the beans with matching type. Your service then could look like this
#Autowired List<BugTracker> trackers; //autowired on field for brevity
boolean processIssueTicketRequest(Issue issue){
for (BugTracker t : trackers)
if (t.canWorkWithGivenIssue(issue))
return t.createAndSendIssue(issue);
return false;
}
Turn the type into an enum and let the BugTracker decide if it can handle it. Then inject a collection of all BugTracker instances, iterate over them and if it supports the type call the appropriate method.
public enum SystemType { JIRA, BUGZILLA }
Then add a method, for instance supports(Issue issue), to your BugTracker.
boolean supports(Issue issue);
In the implementations check if it can be handled, for instance in the JiraClient do something like this.
public boolean supports(Issue issue) {
return JIRA == issue.getBugTrackerType();
}
Then in your BugTrackerService get a list of all BugTracker instances, iterate and call the appropriate one.
#Service
public class BugTrackerService {
private final List<BugTracker> bugTrackers;
BugTrackerService(List<BugTracker> bugTrackers) {
this.bugTrackers=bugTrackers;
}
boolean processIssueTicketRequest(Issue issue){
for (BugTracker bugTracker : this.bugTrackers) {
if (bugTracker.supports(issue) ) {
bugTracker.createAndSendIssue(issue);
return true;
}
}
return false;
}
}
Now you are as flexible as you want to be and can support as many as you want.
You can pass on the responsibility of finding out the correct implementation of BugTracker to a BugTrackerFactory.
#Component
class BugTrackerFactory {
#Autowired
private final BugzillaClient bugzillaClient;
#Autowired
private final JiraClient jiraClient;
private static final String JIRA_TYPE = "Jira";
private static final String BUGZILLA_TYPE = "Bugzilla";
public BugTracker getBugTracker(String type) {
if (JIRA_TYPE.equals(type)) {
return jiraClient;
} else if (BUGZILLA_TYPE.equals(type)) {
return bugzillaClient;
} else {
// throw some exception
}
}
}
BugTrackerService :
#Service
public class BugTrackerService {
private final BugTrackerFactory bugTrackerFactory;
#Autowired
BugTrackerService(BugTrackerFactory bugTrackerFactory) {
this.bugTrackerFactory = bugTrackerFactory;
}
boolean processIssueTicketRequest(Issue issue){
return bugTrackerFactory.getBugTracker(issue.getBugTrackerType().bugTrackingSystemType.name).createAndSendIssue(issue);
}
}
I have the following Java class that is uploaded on Amazon's Lambda service:
public class DevicePutHandler implements RequestHandler<DeviceRequest, Device> {
private static final Logger log = Logger.getLogger(DevicePutHandler.class);
public Device handleRequest(DeviceRequest request, Context context) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.defaultClient();
DynamoDBMapper mapper = new DynamoDBMapper(client);
if (request == null) {
log.info("The request had a value of null.");
return null;
}
log.info("Retrieving device");
Device deviceRetrieved = mapper.load(Device.class, request.getDeviceId());
log.info("Updating device properties");
deviceRetrieved.setBuilding(request.getBuilding());
deviceRetrieved.setMotionPresent(request.getMotionPresent());
mapper.save(deviceRetrieved);
log.info("Updated device has been saved");
return deviceRetrieved;
}
}
I also have an Execution Role set that gives me complete control over DynamoDB. My permissions should be perfectly fine since I've used the exact same permissions with other projects that used Lambda and DynamoDB in this exact manner (the only difference being a different request type).
The intended point of this class is to have it be called by API Gateway (API Gateway -> Lambda -> DynamoDB), but for now I simply am trying to test it on Lambda (Lambda -> DynamoDB).
For reference, in case it matters, here is the DeviceRequest class:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "deviceId", "building", "motionPresent" })
public class DeviceRequest {
#JsonProperty("deviceId")
private String deviceId;
#JsonProperty("building")
private String building;
#JsonProperty("motionPresent")
private Boolean motionPresent;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("deviceId")
public String getDeviceId() {
return deviceId;
}
#JsonProperty("deviceId")
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
#JsonProperty("building")
public String getBuilding() {
return building;
}
#JsonProperty("building")
public void setBuilding(String building) {
this.building = building;
}
#JsonProperty("motionPresent")
public Boolean getMotionPresent() {
return motionPresent;
}
#JsonProperty("motionPresent")
public void setMotionPresent(Boolean motionPresent) {
this.motionPresent = motionPresent;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
And here is the Device class:
#DynamoDBTable(tableName="DeviceTable")
public class Device {
private String deviceID;
private String building;
private String queue;
private boolean motionPresent;
#DynamoDBHashKey(attributeName="Device ID")
public String getDeviceID() {
return deviceID;
}
public void setDeviceID(String deviceID) {
this.deviceID = deviceID;
}
#DynamoDBAttribute(attributeName="Motion Present")
public boolean getMotionPresent() {
return motionPresent;
}
public void setMotionPresent(boolean motionPresent) {
this.motionPresent = motionPresent;
}
#DynamoDBAttribute(attributeName="Building")
public String getBuilding() {
return this.building;
}
public void setBuilding(String building) {
this.building = building;
}
#DynamoDBAttribute(attributeName="Queue")
public String getQueue() {
return this.queue;
}
public void setQueue(String queue) {
this.queue = queue;
}
}
Here is the JSON input that I'm trying to test the Lambda with:
{
"deviceId": "test_device_name",
"building": "building1",
"motionPresent": false
}
No exceptions whatsoever are thrown (I've tried wrapping it around a try/catch block) and the lambda timing out is the only thing that happens. I've tried using log/print statements at the very beginning prior to the initialization of the DynamoDB client to see if the request can be read properly and it does appear to properly parse the JSON fields. I've also separated the client builder out and found that the builder object is able to be initialized, but the timing out comes from when the builder calls build() to make the client.
If anyone has any insight into why this timing out is occurring, please let me know!
Turns out that by bumping up the timout period AND the allotted memory, the problem get solved. Not sure why it works since the lambda always indicated that its memory usage was under the previously set limit, but oh well. Wish that in the future Amazon will provide better error feedback that indicates if a lambda needs more resources to run.
Hi i am trying to pass a list of objects of type models.InputTimeSheetDataStore from view to application.java and i am getting No QueryString binder found for type java.util.List[models.InputTimeSheetDataStore]. Try to implement an implicit QueryStringBindable for this type error
in application.java i am passing list of object to view
InputTimeSheetDataStore ITSDS= new InputTimeSheetDataStore();
ITSDS.ConsultantName=EmployeeFilter;
ITSDS.Client=ClientFilter;
ITSDS.Project=ProjectFilter;
ITSDS.Role=EmployeeRoleFilter;
ITSDS.Task=Task;
ITSDS.TimeSheetDate=TimeSheetDate;
ITSDS.Hours=TaskHours;
ITSDS.IsBilled=IsBilled;
ITSDS.Workplace=WorkPlace;
InputTimeSheetList.add(ITSDS);
return ok(TimeSheetInput.render(Consultant.PopulateConsultant(),Client.PopulateClient(),Project.PopulateProject(ClientFilter),
Consultant.PopulateConsultantRole(),Consultant.ConsultantRoleRate(EmployeeRoleFilter),InputTimeSheetList));
in view i am passing that object back to application.java
#(EmployeeList:java.util.List[String],ClientList:java.util.List[String],
ProjectList:java.util.List[String],EmployeeRoleList: java.util.List[String],Rate:String,
CurrentPage:List[InputTimeSheetDataStore])
<form id="TimeSheetEntryForm" name="TimeSheetEntryForm" action="#{routes.Application.save("name","name","name","name","name","name","name","name","name",CurrentPage)}" method="GET">
<code.....>
here is my class file
InputTimeSheetDataStore.java
package models;
public class InputTimeSheetDataStore {
public String ConsultantName;
public String Client;
public String Project;
public String Role;
public String Task;
public String TimeSheetDate;
public String Hours;
public String IsBilled;
public String Workplace;
public String getConsultantName(){
return this.ConsultantName;
}
public String getClient(){
return this.Client;
}
public String getProject(){
return this.Project;
}
public String getRole(){
return this.Role;
}
public String getTask(){
return this.Task;
}
public String getTimeSheetDate(){
return this.TimeSheetDate;
}
public String getHours(){
return this.Hours;
}
public String getIsBilled(){
return this.IsBilled;
}
public String getWorkPlace(){
return this.Workplace;
}
}
my routes is
GET /Application/save controllers.Application.save(EmployeeFilter:String,ClientFilter:String,ProjectFilter:String, EmployeeRoleFilter:String,Task:String,TaskHours:String,TimeSheetDate:String,IsBilled:String,WorkPlace:String,CurrentPage:java.util.List[models.InputTimeSheetDataStore])
can someone help me with the implicit querybinder of type InputTimeSheetDataStore
Thanks in advance
Hi this is the example implementation of QueryStringbindable:
public class InputTimeSheetDataStore implements QueryStringBindable<InputTimeSheetDataStore> {
public String consultantName, client, project;
#Override
public Optional bind(String key, Map data) {
if (data.containsKey("consultantName")) {
this. consultantName = data.get("consultantName").toString();
}
if (data.containsKey("client")) {
this.client = data.get("client").toString();
}
if (data.containsKey("project")) {
this.project = data.get("project").toString();
}
return Optional.of(this);
}
#Override
public String unbind(String key) {
return null;
}
#Override
public String javascriptUnbind() {
return null;
}
}
Extra tips for you, when writing a programming language, make sure you are following the code convention. For example: the convention in Java syntax you must write variable with lower case for the first character;
public String ConsultantName; // this is wrong
public String consultantName; //this is right
Hope it helps.
I am using gwt with gwt-platform and making a server call with the dispatch async. The issue I am running into is that the Action that I am using is not being marked as serializable or being added to the *.gwt.rpc file. When my code run I get a
com.google.gwt.user.client.rpc.SerializationException
at com.google.gwt.user.client.rpc.impl.SerializerBase.getTypeHandler(SerializerBase.java:153)
at com.google.gwt.user.client.rpc.impl.SerializerBase.serialize(SerializerBase.java:125)
at com.google.gwt.user.client.rpc.impl.ClientSerializationStreamWriter.serialize(ClientSerializationStreamWriter.java:183)
at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
at com.gwtplatform.dispatch.shared.DispatchService_Proxy.execute(DispatchService_Proxy.java:33)
at com.gwtplatform.dispatch.client.DefaultDispatchAsync.serviceExecute(DefaultDispatchAsync.java:126)
at com.gwtplatform.dispatch.client.DefaultDispatchAsync.execute(DefaultDispatchAsync.java:...
The Action:
public class FindCallsWithFilterAction extends UnsecuredActionImpl<FindCallsWithFilterResult> {
public FindCallsWithFilterAction() {
}
public Date getAfter() {
return after;
}
public Date getBefore() {
return before;
}
public Long getReferenceNumber() {
return referenceNumber;
}
public String getUser() {
return user;
}
public void setAfter(Date after) {
this.after = after;
}
public void setBefore(Date before) {
this.before = before;
}
public void setReferenceNumber(Long referenceNumber) {
this.referenceNumber = referenceNumber;
}
public void setUser(String user) {
this.user = user;
}
public boolean hasAfter(){
return null != after;
}
public boolean hasBefore(){
return null != before;
}
public boolean hasReferenceNumber(){
return null != referenceNumber;
}
public boolean hasUser(){
return null != user;
}
private Date after = null;
private Date before = null;
private Long referenceNumber = null;
private String user = null;
}
The Action has result and a Handler and the handler is bound in my server module. When I debug the code and look at the Serialization map that gwt generates this action and its result aren't there event though this implements the isSerializable interface (in the super class, it still doesn't work if I use Serializable or isSerializable at this level either). Also when I look into my *.gwt.rpc file the class is not in there either. I'm just stuck and was hoping some one would know what to do or what was wrong.
Update: I don't know if it is relevant but I am using spring on the server.
I found my problem. I had forgotten a no-arg constructor in my Result object, also I was using a Builder to create my action and for some reason that was causing the serialization issue once I stopped using the Builder pattern everything ran smoothly.