I created a table in AWS DynamoDB which I'll be using for a basic questions and answers forum I'm developing and after table creation and some successful tests where I was able to insert data I decided to add an attribute for storing date of question, which I called time_stamp but for an unknown reason for me I'm not being able to refresh table structure, I mean, data is still saved with no errors but with no time_stamp field.
I tried deleting the table and recreating several times and modifying time_stamp data type with no success so I'm lost and I hope anyone can help me. I thought the only neccesary thing to alter table structure in DynamoDB is just modifing the mapping class in Java but cannot make it to work.
My mapping class is the next:
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*;
#DynamoDBTable(tableName = "community_questions")
public class CommunityQuestion {
private long question_id;
private String time_stamp;
private String user_id;
private String subject;
private String question;
#DynamoDBHashKey(attributeName = "question_id")
public long getQuestionId() { return question_id; }
public void setQuestionId(long questionId) { this.question_id = questionId; }
#DynamoDBAttribute (attributeName = "time_stamp")
public String geTimeStamp() {
return time_stamp;
}
public void setTimeStamp(String timeStamp) {
this.time_stamp = timeStamp;
}
#DynamoDBAttribute (attributeName = "user_id")
public String getUserId() {
return user_id;
}
public void setUserId(String userId) {
this.user_id = userId;
}
#DynamoDBAttribute(attributeName = "subject")
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
#DynamoDBAttribute(attributeName = "question")
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
}
All data is being saved with no errors but time_stamp won't!!
I'm using mapper.save for saving operations.
Maybe anything I should refresh in AWS console?? Can't find anything.
Please help, and many thanks in advance.
There is a typo in your code. Rename geTimeStamp to getTimeStamp
DynamoDbMapper considers only methods with exactly "get" or "is" prefixes, and then checks for annotations on those in a second step. Its not picking up your added property because of that.
/**
* Returns whether the method given is a getter method we should serialize /
* deserialize to the service. The method must begin with "get" or "is",
* have no arguments, belong to a class that declares its table, and not be
* marked ignored.
*/
private static boolean isRelevantGetter(Method m) {
(soure)
Related
How do you save a JSON Array as an item attribute? AWS documentation is the absolute worst thing ever - it contradicts itself, a lot of things are either redundant or only partially explained, some things aren't explained at all - I don't know how anyone manages to use it.
Anyway, suppose I have a table called Paths, and a path has a name, an ID, and a list of LatLngs (formatted as a JSON Array)
In the class definition for this table, I have
#DynamoDBTable(tableName = "Paths")
public class Path {
private String id;
private String name;
private JSONArray outlineJSON;
with getters and setters like
#DynamoDBRangeKey(attributeName = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
which works fine for strings, booleans and numbers, and the object saves successfully to the table.
AWS documentation mentions JSON several times, and says it can handle lists, but it doesn't explain how to use lists or give any examples.
I used #DynamoDBHashKey for the id, #DynamoDBRangeKey for name, and #DynamoDBAttribute for other strings, numbers or booleans, and I tried it here
#DynamoDBAttribute(attributeName = "outline")
private JSONArray getOutlineJSON() {
return outlineJSON;
}
private void setOutlineJSON(JSONArray outlineJSON) {
this.outlineJSON = outlineJSON;
}
It successfully saved the object but without the array.
How do I save the array? I can't find an explanation anywhere. I think #DynamoDBDocument might have something to do with it, but all the documentation on the subject gives unrelated examples, and I can't find any using a list like my in situation.
EDIT: For now, I have a working solution - I can easily convert my lists to JSONArrays and then convert those to Strings, and vice-versa.
You can define your class to be something like
#DynamoDBTable(tableName = "Paths")
public class Path {
private String id;
private String name;
private LatLang latLangs;
#DynamoDBHashKey(attributeName="id")
public String getId() { return id;}
public void setId(String id) {this.id = id;}
#DynamoDBRangeKey(attributeName = "name")
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#DynamoDBDocument
public static class LatLang{
public String lat;
public String lang;
}
}
I am working with a web service that stores POJOs in a MongoDB. I want to make use of Mongo's 'expireAfterSeconds' time to live feature, to clear out old documents in my collection after a certain period of time.
Initially I had an implementation that sent the date to the REST service using the following JSON:
{
"testIndex": "testIndex",
"name": "hello",
"date": "2016-05-09T11:00:39.639Z"
}
The above code created the document in the collection, and with the following annotation, deleted the document after 10 seconds.
#Indexed (expireAfterSeconds=10)
private Date date;
After implementing this code, I decided I wanted to generate the date only on the Java side, meaning the JSON is now as follows:
{
"testIndex": "testIndex",
"name": "hello"
}
Then I have a constructor in the POJO using JsonCreator from Jackson
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = testIndex;
this.createdAt = new Date();
this.name = name;
}
From reading the documentation here I believe this should flag the constructor to be used when creating a new object. The testIndex and name fields are populated as before. However with this implementation, each time I check the document in my mongo the date value is 'null'. If I change the text for one of the string values to 'hello from the constructor', the constructor appears not to be called as the initial text contained in the JSON is what is added to the database.
POJO
`
#Document(collection = "test")public class TTLTestVO {
#Id private String _id;
#Indexed
private String testIndex;
#Indexed (expireAfterSeconds=10)
private Date createdAt;
private String name;
#JsonIgnore
public TTLTestVO() {
// default
}
#JsonCreator
public TTLTestVO (#JsonProperty("testIndex") String testIndex, #JsonProperty("name") String name) {
this.testIndex = "hello from the constructor";
this.name = name;
}
public String getId() {
return _id;
}
public void setId(String _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTestIndex() {
return testIndex;
}
public void setTestIndex(String testIndex) {
this.testIndex = testIndex;
}
public Date getDate() {
return createdAt;
}
public void setDate(Date date) {
this.createdAt = date;
}
`
After investigating some more I discovered the issue lies with the Spring Framework implementation of #JsonCreator - I removed the imports for org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.annotation and replaced them with com.fasterxml.jackson.annotation. The above implementation now functions as expected.
I have been unable to find an explanation online as to why the spring version isn't working, so if anyone has any ideas please let me/ others know
I had the following entity mapped using JPA 2:
#Entity
public class Translation {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String locale;
#Column(name = "business_code",insertable = true,updatable = false,length = 200,nullable = false)
private String code;
private String text;
// Gettets and setters
....
}
Then I realized than the pair (locale,code) should be unique, so I have changed the entity to have an embeddedId composed by locale, code and I removed the column id from the mapping. This way this pair would act as primary key and they could not be repeated:
As a result:
#Entity
public class Translation {
#EmbeddedId
private TranslationId translationId;
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public TranslationId getTranslationId() {
return translationId;
}
public void setTranslationId(TranslationId translationId) {
this.translationId = translationId;
}
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
And the embeddedId class:
#Embeddable
public class TranslationId implements Serializable{
private static final long serialVersionUID = 1L;
private String locale;
#Column(name = "business_code",insertable = true,updatable = false,length = 200,nullable = false)
private String code;
#Override
public boolean equals(Object obj){
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public int hashCode(){
return HashCodeBuilder.reflectionHashCode(this);
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
I'm using Spring data to query the data, so I have modified also my JPA repository to take in account the new composite Id:
#Repository
public interface TranslationRepository extends JpaRepository<Translation,TranslationId> {
}
So, first of all, does anyone see anything wrong here? Should I do it in another way? As my tests are not passing anymore, if I do a simple translationRepository.findAll(), I'm not getting any result (however there is data in the db), but I'm not getting any error message...
And second - if I get this to work, and then I want Spring data to query all the translations only by locale (not by code), how can I do it? As locale and code are now part of the primary key, can I query them independently?
Since your first problem was already fixed, I'll answer the second question
I want Spring data to query all the translations only by locale (not by code), how can I do it?
locale is still accessible as a single property via translationId. In JPQL you can write
SELECT t FROM Translation t WHERE t.translationId.locale = :locale
In Spring Data repository you can either use the #Query on a custom-named method
#Query("SELECT t FROM Translation t WHERE t.translationId.locale = :locale")
public List<Translation> findByLocale(#Param("locale") String locale)
or go with the slightly longer method name, but automatically handled by Spring Data
public List<Translation> findByTranslationIdLocale(String locale)
I’ve got an application with Hibernate (JPA) which I am using in combination with Jinq. I’ve got a table which lists entities and I want the user to be able to filter it. In the table there are persons listed.
#Entity
public class Person {
private String firstName;
private String surName;
#Id
private int id;
public Person() {
}
public Person(final String pFirstName, final String pSurName, final int pID) {
firstName = pFirstName;
surName = pSurName;
id = pID;
}
public int getId() {
return id;
}
public void setId(final int pID) {
id = pID;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(final String pFirstName) {
return firstName = pFirstName;
}
public String getSurName() {
return surName;
}
public void setSurName(final String pSurName) {
surName = pSurName;
}
}
I am using JavaFX for this, but this shouldn’t matter. First thing I tried was to filter the persons by their surname. For filtering, I used Jinq in combination with lambda. My filtering code looks like this:
private List<Person> getFilteredPersons(final String pSurName){
JPAJinqStream<Person> stream = streamProvider.streamAll(Person.class);
stream.where(person -> person.getSurName().contains(pSurName));
List<Person> filteredList = stream.toList();
stream.close();
return filteredList;
}
So the object I am operating on is a normal String. I don’t think that my Person class has anything to do with that. My first thought was, that you can’t use the method boolean contains(...) in lambda because when the error showed up, it said:
Caused by: java.lang.IllegalArgumentException: Could not analyze lambda code
So my question is, is it somehow possible to use the contains-method of a String in lambdacode?
Your question has nothing to do with JPA or lambdas, but everything to do with jinq: it simply doesn't support translating String.contains() to a database query. See http://www.jinq.org/docs/queries.html#N65890 for what is supported.
Well i want to know if there is a much appropriate way to tackle generating auto id with string values, my first idea is creating an auto increment id which we can call auto_id then before saving a new entity I'll query for the latest data inside the db to get the id then I'll add 1 to my auto generate value column that I assign name which is stringValue+(id+1) though I'm concerned on how it will affect the performance as to saving this entity needs two access in db which is fetching and saving... like my question earlier is there a much appropriate way to handle this scenario?
And also sorry for my English guys if you want to clarify things with my question kindly ask, thnx in advance..
Here's my code for AttributeModel for hibernate annotation
#Component
#Entity
#Table(name="attribute_info")
public class AttributeModel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="attr_id", nullable=false, unique=true)
private int id;
#Column(name="attr_name")
private String name;
#Column(name="attr_desc")
private String desc;
#Column(name="attr_active")
private int active;
#Column(name="attr_abbr")
private String abbr;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="stats_id", referencedColumnName="stats_id")
private BaseStatisticModel baseStats;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getActive() {
return active;
}
public void setActive(int active) {
this.active = active;
}
public String getAbbr() {
return abbr;
}
public void setAbbr(String abbr) {
this.abbr = abbr;
}
public BaseStatisticModel getBaseStats() {
return baseStats;
}
public void setBaseStats(BaseStatisticModel baseStats) {
this.baseStats = baseStats;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I can only say "Don't do it". How is a String ID like "str10001" better than 10001? It can't be an optimization as strings take more memory and more time. So I guess you need to pass it to some String-expecting method later.
If so, then pass "str" + id instead. Constructing the string on the fly surely won't saturate your server.
If not, then let us know what you actually need rather than what you think it could help you to achieve it.
I'm pretty sure, Hibernate can't do it. It couldn't some long time ago I checked it recently and it makes no sense (in any case, it's not a feature crowds would request).