Lombok Annotations with DynamoDB annotations - amazon-dynamodb

I have a DAO like:
#Getter
#Setter
#DynamoDBTable(tableName="tableName")
public class DAO {
#DynamoDBHashKey
private String field1;
#DynamoDBIndexHashKey(globalSecondaryIndexName="index_name")
#DynamoDBRangeKey
private String field2;
}
Problem is when I am trying to use the DAO to make a load call using DynamoDBMapper with field1 as the hash key to obtain the item, it throws a DynamoDBException saying:
Null key found for public DAO.getField2()
but actually table has value corresponding to field2.
Question, is this because of Lombok annotation instead of the manual mutator code and or in general we use Lombok and DynamoDBAnnotations together?

Here is a little more of an explanation and a TL;DR
You are calling the load method, which is mapped to the GetItem call. The DynamoDBMapper is trying to map that request based on your annotations. Your class has the #DynamoDBRangeKey annotation, and the GetItem call needs the full primary key to get the item, which means that the mapper will build out the primary key for the object.
Since Lombok has already generated your code (before runtime), it is not affecting the annotations you have already placed. And also since your annotations are on the fields rather than applying them to the getters, the mapper it is calling the generated Lombok getter. When it tries to serialize into a request, however, that getter is returning null because you have only set the hashKey.
TL;DR: load() translates to GetItem API which requires both the hashKey and the rangeKey since both annotations are present on your class.

Related

springboot+mybatis, About Native Dao development

I'm trying a new development method.
In mybatis3, I write mapper.java and mapper.xml usually.
I know, the sql statements is corresponded by sqlId(namespace+id).
I want to execute the sql statement like this :
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
but I get a error:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.JinBoot.test
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at cn.tianyustudio.jinboot.dao.BaseDao.select(BaseDao.java:20)
at cn.tianyustudio.jinboot.service.BaseService.select(BaseService.java:10)
at cn.tianyustudio.jinboot.controller.BaseController.test(BaseController.java:21)
here is my BaseDao.java
public class BaseDao {
private static SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
public static List<Map> select(String sqlId, Map param) {
try {
factoryBean.setDataSource(new DruidDataSource());
SqlSessionFactory sessionFactory = factoryBean.getObject();
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
here is UserMapper.xml
<mapper namespace="mapper.JinBoot">
<select id="test" parameterType="hashMap" resultType="hashMap">
select * from user
</select>
</mapper>
the application.properties
mybatis.mapperLocations=classpath:mapper/*.xml
I start the project, the send a http request, after controller and service ,the param 'sqlId' in BaseDao is 'mapper.JinBoot.test' (see error info).
In method 'BaseDao.select', both the parameter and the result type is Map.
So I don't want to create UserMapper.java, I want try it.
How can I resolve it? What's the malpractice of this way?
This does not work because spring boot creates its own SqlSessionFactory. And the option in application.properties that specifies where mappers should be looked for is only set for that SqlSessionFactory. You are creating unrelated session factory in your DAO and it does not know where to load mappers definition.
If you want to make it work you need that you DAO is spring managed so that you can inject mybatis session factory into it and use it in select. This would also require that you convert select into non static method.
As I understand you want to have only one method in you base DAO class and use it in individual specific DAO classes. I would say it makes little sense. If the method returns Map there will be some place that actually maps this generic type to some application specific types. This would probably be in the child DAOs. So you still need to create the API of the child DAO with the signature that uses some input parameters and returns some domain objects. And that's exactly what you want to avoid by not creating mybatis mapper classes.
The thing is that you can treat your mytabis mappers as DAOs. That is you mappers would be your DAOs. And you don't need another layer. As I understand now you have two separate layers - DAO and mappers and you want to remove boilerplate code. I think it is better to remove DAO classes. They are real boilerplate and mybatis mapper can serve as DAO perfectly. You inject it directly to you service and service depends only on the mapper class. The logic of the mapping is in the mapper xml file. See also answer to this question Can Spring DAO be merged into Service layer?

How can I use a DataTransformer transform with the FosRestBundle view layer

I've using a DataTransformer on my form to reverseTransform a decimal value send by the client into a Money/Money object.
This works well as expected, however when I return the data to the client using the FosRestBundle view layer, I'm not sure how I can use that transformer to transform it back into a decimal value for the client?
If you are using JMSSerializer with FOSRestBundle the serializer usually accesses the values of your object using reflection so the getters aren't touched.
You can however set the access type for the property or all of the properties in the object to the public method (getters/setters) using the access_type setting.
For Annotation you would use..
use JMS\Serializer\Annotation\AccessType;
class YourClass
{
/**
* #AccessType("public_method")
*/
private $money;
....
}
For more info see:
Annotations: http://jmsyst.com/libs/serializer/master/reference/annotations#accessor
XML: http://jmsyst.com/libs/serializer/master/reference/xml_reference
YAML: http://jmsyst.com/libs/serializer/master/reference/yml_reference

Complex bean validation

How can I validate the below class using validator (JSR303) API? This should be done using Hibernate Validator API.
Suppose TesterBatters class itself has some validation. How can I validate those?
public class Example {
private String jseId;
private String jseType;
private String jseName;
private Double jsePpu;
private TesterBatters jseBatters;
private List<TesterToppin> jseTopping;
public String getTesterId() {
return jseId;
}
}
You basically have to add constraint annotations such as #NotNull, #Size etc. to the elements of your model (i.e. the properties and/or classes) and perform a validation of these constraints at a suitable point of time (e.g. when persisting objects or processing data entered by the user into a GUI) using the javax.validation.Validator API.
To recursively apply a validation to referenced objects, use the #Valid annotation.
I recommend to have a look into the Hibernate Validator reference guide which explains in detail how to work with Bean Validation.

Example of how to add secondary index when storing object in Riak with Java Client?

I am storing a hash-map in a riak bucket like this:
bucket.store(key, docHashMap).execute();
I would like to store the object with a secondary index.
How would I accomplish this? I am aware that the IRiakObject has a addIndex method, but how do I access the IRiakObject before it is stored?
I would think that what I am trying to do is the expected use-case, yet I am not able to find any documentation or examples on this. If you can point me to one that would be greatly appreciated.
Thanks!
Update:
#Brian Roach answered this on the Riak mailing list and below. Here is the custom class that I wrote that extends the HashMap:
class DocMap extends HashMap<String, Object> {
/**
* Generated id
*/
private static final long serialVersionUID = 5807773481499313384L;
#RiakIndex(name="status") private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
I can still use the object as an ordinary hashmap and store keys and values, but it will also write "status" to a secondary index (and actually end up being called "status_bin" since it's a string.
If you're just passing in an instance of the core Java HashMap ... you can't.
The way the default JSONConverter works for metadata (such as indexes)
is via annotations.
The object being passed in needs to have a field annotated with
#RiakIndex("index_name"). That field can be a Long/Set<Long> or
String/Set<String> (for _int and _bin indexes respectively).
These are not converted to JSON so they won't affect your serialized
data. You can have multiple fields for multiple indexes.
You don't have to append "_int" or "_bin" to the index name in the
annotation - it's done automatically based on the type.
Easiest thing to do woud be to extend HashMap and simply add the
annotated field(s).

Unable to delete child entities from a POCO using Unit Of Work pattern

I am using POCO classes on an EF4 CTP5 project and I am having trouble deleting child properties. Here's my example (hopefully not too long).
Relevant Portions of the Tour Class
public partial class Tour
{
public Guid TourId { get; private set; }
protected virtual List<Agent> _agents { get; set; }
public void AddAgent(Agent agent)
{
_agents.Add(agent);
}
public void RemoveAgent(Guid agentId)
{
var a = Agents.Single(x => x.AgentId == agentId);
_agents.Remove(Agents.Single(x => x.AgentId == agentId));
}
}
Command Handler
public class DeleteAgentCommandHandler : ICommandHandler<DeleteAgentCommand>
{
private readonly IRepository<Core.Domain.Tour> _repository;
private readonly IUnitOfWork _unitOfWork;
public DeleteAgentCommandHandler(
IRepository<Core.Domain.Tour> repository,
IUnitOfWork unitOfWork
)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
public void Receive(DeleteAgentCommand command)
{
var tour = _repository.GetById(command.TourId);
tour.RemoveAgent(command.AgentId);
// The following line just ends up calling
// DbContext.SaveChanges(); on the current context.
_unitOfWork.Commit();
}
}
Here's the error that I get when my UnitOfWork calls DbContext.SaveChanges()
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
This is happening because EF wont just automatically delete the an Agent entity from the database just because it has been removed from the Agents collection in my Tour class.
I need to explicitly call dbContext.Agents.DeleteObject(a);, but my problem is, I don't have access to the dbContext from within my POCO.
Is there any way to handle this scenario?
With your current architecture I am afraid you need to feed your DeleteAgentCommandHandler with a second repository (IRepository<Core.Domain.Agent>, I guess) and then call something like Delete(command.AgentId) on that second repository.
Or you could extend your IUnitOfWork to be a factory of repositories, so the interface would get an additional method like T CreateRepository<T>() which allows you to pull any instance of your generic repository from the unit of work. (Then you only need to inject IUnitOfWork into the DeleteAgentCommandHandler, and not the repositories anymore.)
Or stay away from generic repositories in your business/UI layer. If Agent is completely dependent on Tour it doesn't need to have a repository at all. A non-generic ITourRepository could have methods to handle the case of removing an agent from a tour in the database layer appropriately.
This does seem like something that should work. I've found this post which suggests this feature is being investigated for future versions:
http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/58a31f34-9d2c-498d-aff3-fc96988a3ddc/
I've also found another post (somewhere - unfortunately I lost it) which suggested adding the parent entity's key to the child entity in your DbContext OnModelCreating method like this:
modelBuilder.Entity<Agent>()
.HasKey(AgentId)
.HasKey(TourId);
Currently this throws an exception at runtime using code-first, although I have got this working when using an EDMX file by hacking the XAML to include the parent key in the store data model as well as the conceptual data model. I think this difference in behaviour is because in the case of the EDMX file, EF trusts that the store metadata it holds is accurate, whereas code-first checks the database to see whether it's model matches.
Another way which may work although I haven't yet tried it yet, is to include the parent key as a compound key in the child table so that code-first is happy. Obviously changing the database or hacking the XAML are both less than ideal and workarounds at best.

Resources