DynamoDB/Jackson removing 'is' prefix from property name of the entity [duplicate] - java

I have a dynamodb table named opx_user_profiles. The entity is shown below, however the attribute user_profile_id is getting saved as userProfileID in the table, even though the #DynamoDBAttribute(attributeName = USER_PROFILE_ID) is specified on the attribute. Other attributes like date_created are getting saved as expected.
I have read the documentation but still not able to find the root cause of the issue. Is it is a bug in dynamo DB?
#DynamoDBTable(tableName = "opx_user_profiles")
public class UserProfileEntity implements Serializable
{
public static final String USER_PROFILE_ID="user_profile_id";
public static final String DATE_CREATED = "date_created";
public static final String EXPIRY_DATE = "expiry_date";
public static final String USERNAME ="username";
public static final String CONTACT_NAME ="contact_name";
private static final long serialVersionUID = 1L;
#DynamoDBAttribute(attributeName = USER_PROFILE_ID)
private Integer userProfileId;
#DynamoDBAttribute(attributeName = USERNAME)
private String userName;
#DynamoDBAttribute(attributeName = CONTACT_NAME)
private String contactName;
#DynamoDBAttribute(attributeName = DATE_CREATED)
private Date dateCreated;
#DynamoDBAttribute(attributeName = EXPIRY_DATE)
private long expiryDate;
public Integer getUserProfileID()
{
return userProfileId;
}
public void setUserProfileID(Integer userProfileId)
{
this.userProfileId = userProfileId;
}
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getContactName()
{
return contactName;
}
public void setContactName(String contactName)
{
this.contactName = contactName;
}
public Date getDateCreated()
{
return dateCreated;
}
public void setDateCreated(Date dateCreated)
{
this.dateCreated = dateCreated;
}
}

Even though the official AWS documentation says we may apply the annotation #DynamoDBAttribute class field, I could not make it work like this. However, as seen in this AWS example, I could apply without any problem the annotation to the getter methods.
Please try the following:
#DynamoDBTable(tableName = "opx_user_profiles")
public class UserProfileEntity implements Serializable
{
public static final String USER_PROFILE_ID="user_profile_id";
...
private Integer userProfileId;
...
#DynamoDBAttribute(attributeName = USER_PROFILE_ID)
public Integer getUserProfileID()
{
return userProfileId;
}
public void setUserProfileID(Integer userProfileId)
{
this.userProfileId = userProfileId;
}
...
}

One more option.
If you want to reduce code boilerplates you might use Lombok's #Getter this way:
#Getter(onMethod = #__({#DynamoDbAttribute("address")}))
private String address;
p.s.: It won't impact performance cause the code generation happens not in runtime but the entity looks better IMO.

Related

jpa metamodel how to get table name

Entity:
#Entity
public class MyAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String userId;
private String password;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Naming strategy:
public class HibernateNamingStrategy extends PhysicalNamingStrategyStandardImpl implements Serializable {
private static final long serialVersionUID = -4772523898875102775L;
#Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
#Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
protected static String addUnderscores(String name) {
final StringBuilder buf = new StringBuilder(name.replace('.', '_'));
for (int i = 1; i < buf.length() - 1; i++) {
if (Character.isLowerCase(buf.charAt(i - 1)) && Character.isUpperCase(buf.charAt(i))
&& Character.isLowerCase(buf.charAt(i + 1))) {
buf.insert(i++, '_');
}
}
return buf.toString().toLowerCase();
}
}
JPA metamodel:
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(MyAccount.class)
public abstract class MyAccount_ {
public static volatile SingularAttribute<MyAccount, String> password;
public static volatile SingularAttribute<MyAccount, Integer> id;
public static volatile SingularAttribute<MyAccount, String> userId;
public static volatile SingularAttribute<MyAccount, String> email;
}
I am going to do something like below:
Join<Employee,MyAccount> project = emp.join("my_account", JoinType.LEFT);
I don't see any table name related attribute auto-generated in the MyAccount_ metamodel. How can I use metamodel table name in the join criteria (I don't want to use hardcoded string)?
PS: I am using Spring MVC and naming strategy which all camel case is separated by underscore.
It is too bad to hear that (from #Neil Stockton), it is not part of the metamodel, I think it really should be included.
Anyway, my code doesn't have annotation because I am using implicit naming strategy.
So by doing this, it is not working, it got NullPointerException:
System.out.println("Table_Name: " + MyAccount.class.getAnnotation(Table.class).name());
So the simplest way, is to reuse my function addUnderscores (change it to public):
System.out.println("Table_Name: " + HibernateNamingStrategy.addUnderscores(MyAccount.class.getSimpleName()));
Although code become longer but I think it is better than hardcoded string instead.
Hope this help others too.

Annotation #Column package javax.persistence with error in the use spring data

I'm using Spring Data and I'm getting this exception and I'm not understanding why.
The dataCadastro field in the domain is the only field with a different name in the database. In the base is as datacad
Repository
public interface IRepositorioUsuario extends CrudRepository<Usuario, Long> {
}
Service
#Stateless
public class UsuarioService {
#Inject
IRepositorioUsuario usuarioRepositorio;
public void buscar() {
usuarioRepositorio.findAll().forEach(u -> System.out.println(u.getNome()));
}
}
Domain
#Entity
#Table(name="TUSUARIO")
public class Usuario implements Serializable {
private static final long serialVersionUID = -5427866189669150032L;
private Long codigo;
private String nome;
private String login;
private String senha;
#Column(name="datacad") // query error.....
private Date datacadastro;
private Boolean situacao;
#Id
public Long getCodigo() {
return codigo;
}
public void setCodigo(Long codigo) {
this.codigo = codigo;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
public Date getDatacadastro() {
return datacadastro;
}
public void setDatacadastro(Date datacadastro) {
this.datacadastro = datacadastro;
}
public Boolean getSituacao() {
return situacao;
}
public void setSituacao(Boolean situacao) {
this.situacao = situacao;
}
// Omitting hasCode
Error Query
SQL Error: 1054, SQLState: 42S22
Unknown column 'usuario0_.datacadastro' in 'field list'
select
usuario0_.codigo as codigo1_0_,
usuario0_.datacadastro as datacada2_0_,
usuario0_.login as login3_0_,
usuario0_.nome as nome4_0_,
usuario0_.senha as senha5_0_,
usuario0_.situacao as situacao6_0_
from TUSUARIO usuario0_
With the annotation #Column(name = datacad) in getDataCadastro
Seccess
select
usuario0_.codigo as codigo1_0_,
usuario0_.datacad as datacad2_0_,
usuario0_.login as login3_0_,
usuario0_.nome as nome4_0_,
usuario0_.senha as senha5_0_,
usuario0_.situacao as situacao6_0_
from TUSUARIO usuario0_
It is because you are using #Id annotation on the getter method. And so the jpa looks only at the getters to derive the column names and ignores the #column annotation on the field but starts working when you place it on the getter.
As an exercise, you can move Id annotation to field level and should see it working again.
It is recommended to place jpa annotations either at field level or getters. but not to mix

Saving imported objects to DynamoDB in a java application

I am trying to save an object into DynamoDB. I know that the easiest way to do this is to annotate the object with #DynamoDBDocument.
However, in my case, the objects I want to save belong to a package that I can't modify.
I am using the java sdk.
import not.my.package.Outsider;
#DynamoDBTable(tableName = "DynamoTable")
public class DynamoTable {
private Outsider outsider;
//getters...
//setters...
}
Any ideas on how I can save these objects? I do not want to save them as a string as we are using a Dynamo to SQL plugin for our business purposes.
Thanks.
Firstly, the OP doesn't have any information about partition key and sort key. The below code auto generates the partition key using annotation #DynamoDBAutoGeneratedKey. You can change it based on your use case.
Order class - Similar to DynamoTable
#DynamoDBTable(tableName = "Order")
public class Order implements Serializable {
private static final long serialVersionUID = -3534650012619938612L;
private String orderId;
private String productName;
private Integer createDate;
private Outsider outsider;
#DynamoDBHashKey(attributeName = "orderId")
#DynamoDBAutoGeneratedKey
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
#DynamoDBAttribute(attributeName = "productName")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
#DynamoDBAttribute(attributeName = "createDate")
public Integer getCreateDate() {
return createDate;
}
public void setCreateDate(Integer createDate) {
this.createDate = createDate;
}
#DynamoDBAttribute(attributeName = "outsider")
public Outsider getOutsider() {
return outsider;
}
public void setOutsider(Outsider outsider) {
this.outsider = outsider;
}
}
Outsider class:-
The attributes in outsider class will be saved as Map attribute in DynamoDB table.
#DynamoDBDocument
public class Outsider implements Serializable{
private static final long serialVersionUID = 4449726365885112352L;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Code to save data:-
This code should work as long as you have dynamoDBClient object. I have used Spring to inject the object to my service class. There are multiple ways.
public Boolean createOrderWithOutsider(String productName, Outsider outsider) {
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient);
Order order = new Order();
order.setProductName(productName);
order.setOutsider(outsider);
dynamoDBMapper.save(order);
System.out.println("Order id : " + order.getOrderId());
return true;
}
Test code:-
#Test
public void createOrderWithOutsider() {
Outsider outsider = new Outsider();
outsider.setFirstName("John");
outsider.setLastName("Micheal");
Assert.isTrue(tableOperations.createOrderWithOutsider("Pepsi", outsider));
}
Connection sample:-
<bean id="amazonDynamoDB" class="com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient">
<constructor-arg ref="amazonAWSCredentials" />
<property name="endpoint" value="${amazon.dynamodb.endpoint}" />
</bean>
Autowired in service class:-
#Autowired
private AmazonDynamoDBClient dynamoDBClient;
Sample data saved in table:-

Save and retrieve Arraylists using ActiveAndroid ORM and Retrofit

I am using Retrofit and ActiveAndroid ORM in my application. I have the following Model class:
#Table(name = "formresource")
public class FormResource extends Model implements Serializable{
#Column(name="name")
#SerializedName("name")
#Expose
private String name;
#Column
#SerializedName("resources")
#Expose
private List<FormResource> resources = new ArrayList<FormResource>();
#Column(name = "valueReference")
#SerializedName("valueReference")
#Expose
private String valueReference;
#Column(name = "uuid")
#SerializedName("uuid")
#Expose
private String uuid;
#Column(name = "display")
#SerializedName("display")
#Expose
private String display;
#Column(name = "links")
#SerializedName("links")
#Expose
private List<Link> links = new ArrayList<Link>();
public FormResource()
{
super();
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
public List<Link> getLinks() {
return links;
}
public void setLinks(List<Link> links) {
this.links = links;
}
public String getValueReference() {
return valueReference;
}
public void setValueReference(String valueReference) {
this.valueReference = valueReference;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<FormResource> getResources() {
return resources;
}
public void setResources(List<FormResource> resources) {
this.resources = resources;
}
}
Now, I obtain the Formresources once while starting the application and save it. Then in another activity I use the saved formresources to populate a listview. This much works fine. Now, I want to access the nested formresources like this:
formresourcelist.get(position).getResources();
This always returns a blank list of List<FormResource> . What should I do to properly save and retrieve this list? I need to maintain compatibility with Retrofit at the same time.
I think I found a workaround. I made the following changes in the Model Class:
#Table(name = "formresource")
public class FormResource extends Model implements Serializable{
Gson gson=new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Type formresourcelistType = new TypeToken<List<FormResource>>(){}.getType();
#SerializedName("resources")
#Expose
private List<FormResource> resources = new ArrayList<FormResource>();
#Column(name = "resources")
#Expose
private String resourcelist;
public List<FormResource> getResources() {
return resources;
}
public void setResources(List<FormResource> resources) {
this.resources = resources;
}
public void setResourcelist()
{
this.resourcelist=gson.toJson(resources,formresourcelistType);
}
public List<FormResource> getResourceList() {
List<FormResource> resourceList=gson.fromJson(this.resourcelist,formresourcelistType);
return resourceList;
}
}
Basically I am serializing the ArrayList and persisting it as a String in the DB. While saving a FormResource, I do the following:
formresourceObject.setResourcelist();
formresourceObject.save();
Since you're using Retrofit to populate the FormResource data, you should not initialize any fields inside the model.
This line is the problem :
private List<FormResource> resources = new ArrayList<FormResource>();
try removing the initialization and just declare the field like :
private List<FormResource> resources;
and then try calling formresourcelist.get(position).getResources();
Good luck!

How create a new FieldType in solr schema.xml

I'm new to Solr,
I'm developing an application for my thesis, a kind of search semantic engine ,i use springsource, (something like that siri or s-voice). I use springsource and Solr with Indexing my documents,but i have some problem with fieldType. My schema requires a custom model (not only a class with a string parameter):
public class IndexedObject{
private String id;
private ArrayList<String> features;
private ArrayList<Semantic> semantic;
private String score;
private String time;
private int status;
#XmlElement(name="time")
public String getTime() {
return time;
}
#Field
public void setTime(String time) {
this.time = time;
}
#XmlElement(name="status")
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
#XmlElement(name="score")
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
#XmlElement(name="id", required=true)
public String getId() {
return id;
}
#Field
public void setId(String id) {
this.id = id;
}
#XmlElementWrapper(name = "features")
#XmlElement(name = "feature")
public ArrayList<String> getFeatures() {
return features;
}
#Field
public void setFeatures(ArrayList<String> features) {
this.features = features;
}
#XmlElementWrapper(name = "semantics")
#XmlElement(name = "semantic")
public ArrayList<Semantic> getSemantic() {
return semantic;
}
#Field
public void setSemantic(ArrayList<Semantic> semantic) {
this.semantic = semantic;
}
I have a problem with ArrayList semantic that use a custom class that i wrote.
The question is: How I create a custom FieldType to add to solr schema.xml. If I start my code I get this error :solr error unknown field semantic. and it does not work.
Can anybody help me?
Please refer to the following links for guidance on modifying the Solr Schema.
Documents, Fields and Schema Design
Schema XML

Categories

Resources