path variable won't bind to controller method parameter object property - spring-mvc

I can't make Spring MVC bind my path variables to my custom object.
Given following controller method:
#GetMapping(value = "/customer/{type}/{id}/account/{accountNo}/operation")
public Mono<Response> getAccountHistory(CustomerData customerData) {
System.out.println("Customer data: " + customerData);
return Mono.just(Response.builder().build());
}
DTO class:
public class CustomerData {
private String id;
private String type;
private String accountNo;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
#Override
public String toString() {
return "CustomerData{" +
"id='" + id + '\'' +
", type='" + type + '\'' +
", accountNo='" + accountNo + '\'' +
'}';
}
And test snippet
client.get().uri(uriBuilder -> uriBuilder
.path("/customer/{type}/{id}/account/{accountNo}/operation")
.build("TYPE", "12345678", "11102055610000350203650330")
).accept(APPLICATION_JSON)
.exchange()
I get output
Customer data: CustomerData(id=null, type=null, accountNo=null)
So no path variable is bound to the object.
However binding to simple types using #PathVariable works like a charm - changing the controller method definition to
#GetMapping(value = "/customer/{type}/{id}/account/{accountNo}/operation")
public Mono<Response> getAccountHistory(#PathVariable("type") String type, #PathVariable("id") String id,
#PathVariable("accountNo") String accountNo) {
val customerData = new CustomerData();
customerData.setAccountNo(accountNo);
customerData.setType(type);
customerData.setId(id);
System.out.println("Customer data: " + customerData);
return Mono.just(Response.builder().build());
}
Produces the expected output:
Customer data: CustomerData{id='12345678', type='TYPE', accountNo='11102055610000350203650330'}
What am I doing wrong?
My Controller class is annotated with
#RestController
public class Controller {

I just copied your code to an empty Spring Boot project and it works fine in the browser when accessing it like so:
http://localhost:8080/customer/someType/someId/account/someAccount/operation
Your testing snippet, however, looks incomplete/wrong and does not set all parameters.

#GetMapping(value = "/customer/{type}/{id}/account/{accountNo}/operation")
public Mono<Response> getAccountHistory(#PathParam("type") String type, #PathParam("id") String id, #PathParam("account") String account) {
CustomerData customerData = new CustomerData();
customerData.setType(type);
customerData.setId(id);
customerData.setAccount(account);
System.out.println("Customer data: " + customerData); return Mono.just(Response.builder().build()); }

Related

ASP.NET GET request always returns blank

I'm trying to make an endpoint to return a JSON response. I've tried narrowing it down to just the object and all I receive is {} or [{}] as a response. After debugging I confirmed that the object was being created correctly but when returning the response it was always blank. Below is simplified code but still has the same issue. Any ideas what I'm doing wrong?
[Route("{application}")]
[HttpGet]
public IActionResult Get(string application)
{
List<RequestedSetting> requestedSettings = new List<RequestedSetting>();
RequestedSetting rs = new RequestedSetting("foo", "bar");
requestedSettings.Add(rs);
return Json(requestedSettings);
}
public class RequestedSetting
{
public string Name;
public string Value;
public RequestedSetting(string name, string value)
{
Name = name;
Value = value;
}
}
I've also tried this:
[Route("{application}")]
[HttpGet]
public List<RequestedSetting> Get(string application)
{
List<RequestedSetting> requestedSettings = new List<RequestedSetting>();
RequestedSetting rs = new RequestedSetting("foo", "bar");
requestedSettings.Add(rs);
return requestedSettings;
}
Fields are not supported for serialisation in System.Text.Json. see the docs for more info.
Instead, change your class to use properties:
public class RequestedSetting
{
public string Name { get; set; }
public string Value { get; set; }
public RequestedSetting(string name, string value)
{
Name = name;
Value = value;
}
}

How to query DynamoDB using ONLY Partition Key [Java]?

I am new to DynamoDB and wanted to know how can we query on a table in DynamoDB by using ONLY partition key in JAVA
I have table called "ervive-pdi-data-invalid-qa" and it's Schema is :
partition key is "SubmissionId"
Sort key is "Id".
City (Attribute)
Errors (Attribute)
The table looks like this:
Table
I want to retrieve the sort key value and remaining attributes data by using Partition key using (software.amazon.awssdk) new version of AWS SDK DynamoDB classes.
is it possible to get it? If so, can any one post the answers?
Have tried this:
DynamoDbClient ddb =
DynamoDbClient.builder().region(Region.US_EAST_1).build();
DynamoDbEnhancedClient enhancedClient =
DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
//Define table
DynamoDbTable<ErvivePdiDataInvalidQa> table =
enhancedClient.table("ervive-pdi-data-invalid-qa",
TableSchema.fromBean(ErvivePdiDataInvalidQa.class));
Key key = Key.builder().partitionValue(2023).build();
ErvivePdiDataInvalidQa result = table.getItem(r->r.key(key));
System.out.println("The record id is "+result.getId());
ErvivePdiDataInvalidQa table class is in below comment*
and it is returning "The provided key element does not match the schema (Service: DynamoDb, Status Code: 400, Request ID: PE1MKPMQ9MLT51OLJQVDCURQGBVV4KQNSO5AEMVJF66Q9ASUAAJG, Extended Request ID: null)"
Query you need is documented in one of the examples of AWS Dynamodb Query API for Java.
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withRegion(Regions.US_WEST_2).build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("ervive-pdi-data-invalid-qa");
QuerySpec spec = new QuerySpec()
.withKeyConditionExpression("SubmissionId = :v_id")
.withValueMap(new ValueMap()
.withInt(":v_id", 2146));
ItemCollection<QueryOutcome> items = table.query(spec);
Iterator<Item> iterator = items.iterator();
Item item = null;
while (iterator.hasNext()) {
item = iterator.next();
System.out.println(item.toJSONPretty());
}
A single Query operation can retrieve a maximum of 1 MB of data, see documentation
I have been working with Padma on this issue. We first tried A. Khan's code but could not get passed authentication with v1. Instead we got "WARNING: Your profile name includes a 'profile ' prefix. This is considered part of the profile name in the Java SDK, so you will need to include this prefix in your profile name when you reference this profile from your Java code."
ultimately it could not get the credentials. Our credentials assume IAM roles in .aws/config-i2 file. It works fine in v2 but not v1.
So then we tried v2 of the SDK and have no problems with connecting but we get NULL returned on trying to fetch all records from the table.
In all of the below attempts using v2 of SDK, table data returns NULL
We created this table class
package data;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
#DynamoDbBean
public class ErvivePdiDataInvalidQa {
private int submissionId;
private String id;
private String address1;
private String city;
private String dateOfBirth;
private String errors;
private String firstName;
private String firstNameNormalized;
private String gender;
private String lastName;
private String lastNameNormalized;
private String middleNameInitial;
private String postalCode;
private String rowNumber;
private String state;
private String submissionType;
#DynamoDbPartitionKey
public int getSubmissionId() {
return submissionId;
}
public void setSubmissionId(int submissionId) {
this.submissionId = submissionId;
}
#DynamoDbSortKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAddress1() {
return address1;
}
public void setAddress1(String Address1) {
this.address1 = Address1;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(String dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getErrors() {
return errors;
}
public void setErrors(String errors) {
this.errors = errors;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstNameNormalized() {
return firstNameNormalized;
}
public void setFirstNameNormalized(String firstNameNormalized) {
this.firstNameNormalized = firstNameNormalized;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastNameNormalized() {
return lastNameNormalized;
}
public void setLastNameNormalized(String lastNameNormalized) {
this.lastNameNormalized = lastNameNormalized;
}
public String getMiddleNameInitial() {
return middleNameInitial;
}
public void setMiddleNameInitial(String middleNameInitial) {
this.middleNameInitial = middleNameInitial;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getRowNumber() {
return rowNumber;
}
public void setRowNumber(String rowNumber) {
this.rowNumber = rowNumber;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getSubmissionType() {
return submissionType;
}
public void setSubmissionType(String submissionType) {
this.submissionType = submissionType;
}
}
DynamoDB code to get all records
//Connection
DynamoDbClient ddb = DynamoDbClient.builder().build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
//Define table
DynamoDbTable<ErvivePdiDataInvalidQa> table = enhancedClient.table("ervive-pdi-data-invalid-qa", TableSchema.fromBean(ErvivePdiDataInvalidQa.class));
//Get All Items from table - RETURNING NULL
Iterator<ErvivePdiDataInvalidQa> results = table.scan().items().iterator();
while (results.hasNext()) {
ErvivePdiDataInvalidQa rec = results.next();
System.out.println("The record id is "+rec.getId());
}
Also tried:
DynamoDB code to filter by SubmissionID
AttributeValue attr = AttributeValue.builder()
.n("1175")
.build();
// Get only Open items in the Work table
Map<String, AttributeValue> myMap = new HashMap<>();
myMap.put(":val1", attr);
Map<String, String> myExMap = new HashMap<>();
myExMap.put("#sid", "SubmissionId");
// Set the Expression so only Closed items are queried from the Work table
Expression expression = Expression.builder()
.expressionValues(myMap)
.expressionNames(myExMap)
.expression("#sid = :val1")
.build();
ScanEnhancedRequest enhancedRequest = ScanEnhancedRequest.builder()
.filterExpression(expression)
.limit(15)
.build();
// Get items in the Record table and write out the ID value
Iterator<ErvivePdiDataInvalidQa> results = table.scan(enhancedRequest).items().iterator();
while (results.hasNext()) {
ErvivePdiDataInvalidQa record = results.next();
System.out.println("The record id is " + record.getId());
}

Unable to perform LAZY FETCH operation using JPA in one-to-one relationship

I am trying to lazily fetch PetDetails entity using JPA. However, I get LazyInitialization Exception. I read many solutions for this exception and came to find solution using JOIN FETCH in JPQL. Also people recommended using Criteria queries. However, I am trying to look for a solution if there is a way I can fetch the PetDetails entity the way I want without using queries directly or depending on Criteria API or without using EAGER FETCH. I might be missing something. I would appreciate for any help or suggestion. Below are the code samples:
1. Controller class:
#Controller
public class PetController {
private static Logger LOGGER = Logger.getLogger(PetController.class);
#Autowired
private PetService petService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public void manageAndDisplayPet() {
PetDetails petDetails = new PetDetails();
petDetails.setName("DOG");
Pet pet = new Pet(petDetails);
// save
petService.savePet(pet);
// retrieve
LOGGER.debug("**********************" + petService.getPet());
LOGGER.debug("**********************" + pet.getPetDetails());
}
}
2. PetService class:
#Service
public class PetService {
#Autowired
private PetDAO petDAO;
#Transactional
public void savePet(Pet pet) {
petDAO.savePet(pet);
}
#Transactional
public Pet getPet() {
return petDAO.getPet();
}
}
3. PetDAO class
#Repository
#EnableTransactionManagement
public class PetDAO {
#PersistenceContext(unitName = "petcontext")
private EntityManager entityManagerFactory;
public void savePet(Pet pet) {
entityManagerFactory.persist(pet);
}
public Pet getPet() {
Pet pet = (Pet) entityManagerFactory.find(Pet.class, 1);
return pet;
}
}
4. Pet Entity:
#Entity
#Table(name = "t_pet")
public class Pet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinColumn(name = "pet_details")
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private PetDetails petDetails;
public Pet() {
}
public Pet(PetDetails petDetails) {
this.petDetails = petDetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PetDetails getPetDetails() {
return petDetails;
}
public void setPetDetails(PetDetails petDetails) {
this.petDetails = petDetails;
}
#Override
public String toString() {
return "Pet [id=" + id + ", petDetails=" + petDetails + "]";
}
}
5. PetDetails Entity:
#Entity
#Table(name = "pet_details")
public class PetDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "pet_name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "PetDetails [id=" + id + ", name=" + name + "]";
}
}
Thank you for your help.
Easy thing you can do is to call pet.getPetDetails() inside PetService#getPet. This solution is not very clear, but it will force JPA to fetch entity too. This is solution for your question, but not the good way anyways.
What is the good way?
The good way may depend on your particular usecase:
If you need this details everytime — you should use EAGER_FETCH
If you need it time to time than good solution it to use JPQL with JOIN FETCH
But the best way is to select not entites, but DTOs, which will contain whole information which your application needs and not more. It may be achieved with SELECT NEW expression as described here

Firebase snapshot getValue could not pars int suddenly

I hade a strange happening today with my Firebase project.
Suddenly the
AddressChatMessage chatMessage = snapshot.getValue(AddressChatMessage.class);
parsed everything ok for the AddressChatMessage except for one int.
Took me 2 hour until i tried this, setting the field to public
public int type;
Note I use this code for weeks without problem and today Android studio made some core updated to 2.3.2 and maybe that trigger this strange event.
Here´s the AddressChatMessage.java nothing strange except that the public int type cannot be private, if it is, it will be zero, that too is strange, usually Firebase give out a logcat warning when pojo parsing fails. I have 10 other modell classes like this with plenty of int´s
#IgnoreExtraProperties
public class AddressChatMessage {
// [START Firebase keys inside AddressChatMessage ]
#Exclude
public static final String TYPE = "type";
#Exclude
public static final String SENDER_ID = "senderId";
#Exclude
public static final String MESSAGE = "message";
#Exclude
public static final String FILENAME = "fileName";
#Exclude
public static final String DOWNLOAD_URI = "downloadUri";
#Exclude
public static final String TIME = "time";
// [STOP Firebase keys inside AddressChatMessage ]
public int type;
private String senderId;
private String message;
private String fileName;
private String downloadUri;
#Exclude
private long time;
#Exclude
private String messageId;
public AddressChatMessage() {
}
public AddressChatMessage(int type, String senderUid) {
this.senderId = senderUid;
this.type = type;
}
public AddressChatMessage(int type, String senderUid, String message) {
this.type = type;
this.senderId = senderUid;
this.message = message;
}
private int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getSenderId() {
return senderId;
}
public void setSenderId(String senderId) {
this.senderId = senderId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getDownloadUri() {
return downloadUri;
}
public void setDownloadUri(String downloadUri) {
this.downloadUri = downloadUri;
}
public long getTime() {
return time;
}
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put(TYPE, type);
result.put(SENDER_ID, senderId);
result.put(MESSAGE, message);
result.put(FILENAME, fileName);
result.put(DOWNLOAD_URI, downloadUri);
result.put(TIME, time);
return result;
}
#Exclude
public boolean isTypeNormal() {
return getType() == ChatAdapter.MessageType.NORMAL.ordinal();
}
#Exclude
public boolean isTypeImage() {
return getType() == ChatAdapter.MessageType.IMAGE.ordinal();
}
}
When cleaning the code using Lint. Lint suggested changes like "This can be private instead of public" - I accidentally set the getType() to private access.

How can I retrieve/store a result set to an ArrayList?

How do I use the JdbcTemplate.query()/queryForList() to run a query using namedParameter and store the result set into a List of 'User's?
User Class:
public class User {
String name = null;
String id = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return name;
}
public void setId(String id) {
this.id = id;
}
}
Query:
SELECT name, id FROM USERS where email=:email
I'm looking for something like:
ArrayList<User> userList = jdbcTemplate.query(sql_query,
...some_mapper..., etc);
Seems like the answer to the question is not available at one place, on the Internet. Here's what I found out:
For adding the resultset into a List<>, we can use the NamedParameterJdbcTemplate.query() function:
NamedParameterJdbcTemplate jdbcTemplate;
ArrayList<User> usersSearchResult = (ArrayList<User>) jdbcTemplate.query(
USER_LIST_TP_query,
namedParameters,
new RowMapperResultSetExtractor<User>(new UserRowMapper(), 20));
We also have to define a custom RowMapperResultSetExtractor so that JDBC can understand how to convert each row in the result set to the type User.
private class UserRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getString("ID"));
user.setName(rs.getString("NAME"));
return user;
}
}

Resources