I have an attribute called Attribute which is Set in dynamoDB(not mandatory), all the values for the attributes will be sent through an api which will be added into dynamoDB. I am using
#DynamoDBAttribute(attributename = Attribute)
private set<String> Attribute
public Set<String> getAttribute() {
if(CollectionUtils.isNullOrEmpty(Attribute)) {
return ImmutableSet.of(DEFAULT_ATTRIBUTE);
} else {
return ImmutableSet.copyOf(Attribute);
}
}
public void setAttribute(final Set<String> Attribute) {
if (CollectionUtils.isNullOrEmpty(Attribute)) {
this.categories = ImmutableSet.of();
} else {
this.categories = ImmutableSet.copyOf(Attribute);
}
}
I am expecting my dynamoDB table to have an empty set when we don't pass in an attribute value in the request we use, but instead of that, it is saving DEFAULT_ATTRIBUTE as the value of the field Attribute.
My DynamoDBMapperConfig.Savebehavior has default UPDATE, but I see that while saving a new value all the Savebehavior works the same.
If anyone knows the issue please help me with this, I have been trying to debug this from a long time. I want to know why the value in getAttribute is getting stored as the Attribute value?
Try this instead:
private set<String> Attribute
#DynamoDBTyped(DynamoDBMapperFieldModel.DynamoDBAttributeType.SS)
public Set<String> getAttribute() {
return Attribute;
}
public void setAttribute(final Set<String> Attribute) {
this.Attribute = Attribute;
}
DynamoDBMapper will handle the String Set for you. You just need to use the right annotation.
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.DataTypes.html
Related
(repository with an example of what I'm trying to do is here)
It's my first time using ByteBuddy and I've found myself struggling to merge the contents of two #RequestMapping annotations.
Something like this:
#Validated
#RequestMapping(
path = "/somePrefix",
produces = {"application/text", "application/xml"},
consumes = {"application/text", "application/xml"},
params = {"exampleParam1", "exampleParam2"},
headers = {"key=val", "nokey=val"}
)
public interface ExampleInterface {
#RequestMapping(value = {"/someEndpoint"}, method = {RequestMethod.POST}, produces = {"application/json"}, consumes = {"application/json"})
ResponseEntity<String> someEndpointMethod(String value);
}
And pretending to having this:
public interface ExampleInterface {
#RequestMapping(
value = {"/somePrefix/someEndpoint"},
method = {RequestMethod.POST},
produces = {"application/text", ,application/xml","application/json"},
consumes = {"application/text", "application/xml","application/json"},
params = {"exampleParam1", "exampleParam2"},
headers = {"key=val", "nokey=val"}
)
ResponseEntity<String> someEndpointMethod(String value);
}
I've seen that editing the values can be done replacing the value when the method annotation object is visited, for example:
[...]
#Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
if (Type.getDescriptor(RequestMapping.class).equals(descriptor)) {
return new AnnotationVisitor(Opcodes.ASM9, super.visitAnnotation(descriptor, visible)) {
#Override
public AnnotationVisitor visitArray(String name) {
if ("produces".equals(name)) {
return new AnnotationVisitor(Opcodes.ASM9, super.visitArray(name)) {
#Override
public void visit(String name, Object value) {
// I'd like to receive an array as value, so I can provide one with all values merged
boolean tryToMerge = false;
if (tryToMerge) {
//I cannot return array with everything
Object[] newValue = new Object[]{value};
value = Arrays.copyOf(newValue, newValue.length + originalAnnotation.produces().length);
System.arraycopy(originalAnnotation.produces(), 0, value, newValue.length, originalAnnotation.produces().length);
} else {
//I can only replace a single value
value = originalAnnotation.produces()[0];
}
// How to set an array in produces?
super.visit(name, value);
}
};
} else {
return super.visitArray(name);
}
}
};
} else {
return super.visitAnnotation(descriptor, visible);
}
}
[...]
However, I'm receiving the array values one per one via visit() and I cannot just return an array with the two values I want to merge (["application/text", "application/xml"]) because it's expecting an String object. I can substitute the value that I'm receiving but I cannot add more.
Besides that, the headers and params arrays are not being visited, which seems logical because no values are on those arrays. However, I'm not sure how I should visit those fields in the #RequestMapping on the method so I can insert the values picked from the class one.
What I am missing here?
Thanks in advance.
In such a case, you can override the onEnd() method of AnnotationVisitor. When invoked, you know that all values are processed and you can invoke super.onValue() from there before delegating to super.onEnd(). If you know the replacements beforehand, you can also simply leave the onValue method empty to drop all existing values and then repopulate the array in the end.
I have a javebean linked to a jsp page and have to manage a SET OF A SET.
The javabean structure is something like this:
public class QueryManagement {
...
private BigDecimal prob;
private Set<Set<Axiom>> explanations;
...
public void QueryExecute() {
...
QueryResult r = new QueryResult();
...
prob = r.getProbability();
explanations = r.getExplanations();
...
}
...
public BigDecimal getProb() {
return this.prob;
}
...
}
Now, from the jsp page I'm able to return prob with <%=QueryManagement.getProb()%> but I don't know how to return the vaule of a "Set of a Set". I tried a simple getter returning this.explanations, but it doesn't work. I know I have to return it recursively, but the doc I found at the documentation I found about Set can't help me. Can you explain me how to proceed and why?
public Set<Axiom> getExpl()
{ Iterator itr1 = explanations.iterator();
Set set ;
while(itr1.hasNext())
{
set = (HashSet)itr1.next();
// second iterator for internal set
}
return set ;
}
I am using Swagger version 2 with Java Spring. I have declared a property and it works fine and it generates a drop down list of value I assigned.
#ApiParam(value = "Pass any one Shuttle provider ID from the list", allowableValues = "1,2,3,4,10")
private Long hotelId;
Now, I need a way to populate this list which is passed in allowableValues from my database as it could be random list as well as huge data. How can I assign list of values dynamically from database in this allowableValues?
This question is bit old, I too faced the same problem so thought of adding here which may help some one.
//For ApiModelProperty
#ApiModelProperty(required = true, allowableValues = "dynamicEnum(AddressType)")
#JsonProperty("type")
private String type;
Created a component which implements ModelPropertyBuilderPlugin
#Component
#Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public class ApiModelPropertyPropertyBuilderCustom implements ModelPropertyBuilderPlugin {
private final DescriptionResolver descriptions;
#Autowired
public ApiModelPropertyPropertyBuilderCustom(DescriptionResolver descriptions) {
this.descriptions = descriptions;
}
public void apply(ModelPropertyContext context) {
try {
AllowableListValues allowableListValues = (AllowableListValues) FieldUtils.readField(context.getBuilder(),
"allowableValues", true);
if(allowableListValues!=null) {
String allowableValuesString = allowableListValues.getValues().get(0);
if (allowableValuesString.contains("dynamicEnum")) {
String yourOwnStringOrDatabaseTable = allowableValuesString.substring(allowableValuesString.indexOf("(")+1, allowableValuesString.indexOf(")"));
//Logic to Generate dynamic values and create a list out of it and then create AllowableListValues object
context.getBuilder().allowableValues(allowableValues);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean supports(DocumentationType delimiter) {
return SwaggerPluginSupport.pluginDoesApply(delimiter);
}
}
Similary for ApiParam we can create component which will implement ParameterBuilderPlugin
#Override
public void apply(ParameterContext context) {
#SuppressWarnings("Guava") final Optional<ApiParam> apiParam =
context.resolvedMethodParameter().findAnnotation(ApiParam.class);
if (apiParam.isPresent()) {
final String allowableValuesString = apiParam.get().allowableValues();
//Your logic here
context.parameterBuilder().allowableValues(allowableValues);
}
}
You need to create constructor in SwaggerConfiguration class.
#Autowire service and withdraw data you need from database
assign this to final variable
assign this final variable to allowableValues in annotation
enjoy not efficient api
private final String allowableValues;
public SwaggerConfiguration() {
List<YourEntitiy> list = someService.findAll();
//code to get every value you need and add create comma separated String
StringJoiner stringJoiner = new StringJoiner(",");
stringJoiner.add(list.get(0).getValue());
this.allowableValues = stringJoiner.toString();
}
#ApiParam(allowableValues = allowableValues)
But I think it's bad idea getting all ids from database just to create allowable values. Just validate in api method if that id exist and/or Create new api to get ids from database, use pagination from Spring Data project, like PageImpl<> javadocs
suppose I have defined a List as
private BlockingQueue<MyDelayed> DelayedIds = new DelayQueue<>();
class MyDelayed is like:
private class MyDelayed implements Delayed {
private String myId;
private Long creationTime;
MyDelayed (String myId) {
this.myId= myId;
this.creationTime = System.currentTimeMillis();
}
String getMyId() {
return this.myId;
}
#Override
public long getDelay(TimeUnit unit) {
//TODO
}
#Override
public int compareTo(Delayed o) {
//TODO
}
}
Now suppose that I want to add an Object of class MyDelayed in DelayedIds list.
I can do it by using add function.
But If I want to add obbject in list only if list does not contain an object of class MyDelayed which has the same myId attribute which I am trying to insert.
Obviously DelayedIds .contains(new MyDelayed(myId)) will not work.
Is there any easy way to check this thing ?
Am I missing something ?
You could write something like this and compare every element in the list to see if it contains your id. If at any point you find a matching one you return true, if the loop finished having found none it returns false.
public boolean contains(String id){
for (MyDelayed md : DelayedIds){
if(md.getMyId().equals(id)){
return true;
}
}
return false;
}
Now to check before adding you would do something like:
if(!contains(myNewObject.getMyId())){
DelayedIds.add(myNewObject)
}
Also, I'd suggest that you rename DelayedIds to delayedIds in order to follow coding standards (see Variables).
I am validating the status of a record retrieved from the DB by defining an ENUM as below
public enum RecordStatusEnum {
CREATED("CREATED"),
INSERTED("INSERTED"),
FAILED("FAILED");
private String recordStatusValue;
RecordStatusEnum (String status) {
recordStatusValue= status;
}
public boolean isSuccess() {
return (this.equals(CREATED) || this.equals(INSERTED));
}
}
The method isSuccess() is being used to check the status of the retrieved record ( column status from employee)
if (!(employee.getStatus().isSuccess())) {
// return error
}
As per the new requirement, there are a set of conditions introduced say A,B and C; and for them there is a column in the Employee table 'condition'.
So I need to retrieve the status as well as the condition and see if it belongs to a set which has the combination of both.
For eg : isSuccess() should check if in the following:
CREATED and A
CREATED and B
INSERTED and C
This must be achieved such that it is easy for me to add a new combination say 'INSERTED and B' into the list easily.
What is the best approach for the above problem?
Note : in the actual business scenario there are a whole lot more statuses and checks (eg isFailed() canBeModified() etc) with many different combinations
And any method can be suggested even if it doesn't use ENUMS. I mentioned ENUMS, because I dont want to deviate much from the existing implementation
There are many possibilities, but you could do like this (I removed the String status, which doesn't add any value since it's equal to the name of the enum):
public enum RecordStatusEnum {
CREATED(Condition.A, Condition.B),
INSERTED(Condition.C),
FAILED();
private Set<Condition> successConditions;
RecordStatusEnum(Condition... successConditions) {
this.successConditions = EnumSet.copyOf(Arrays.asList(successConditions));
}
public boolean isSuccess(Condition c) {
return successConditions.contains(c);
}
}
EDIT:
Example with two sets of conditions:
public enum RecordStatusEnum {
CREATED(EnumSet.of(Condition.A, Condition.B),
EnumSet.of(Condition.C)),
INSERTED(EnumSet.of(Condition.C),
EnumSet.of(Condition.B),
FAILED(EnumSet.noneOf(Condition.class),
EnumSet.noneOf(Condition.class));
private Set<Condition> successConditions;
private Set<Condition> modificationConditions;
RecordStatusEnum(Set<Condition> successConditions,
Set<Condition> modificationConditions) {
this.successConditions = successConditions;
this.modificationConditions = modificationConditions;
}
public boolean isSuccess(Condition c) {
return successConditions.contains(c);
}
public boolean canBeModified(Condition c) {
return modificationConditions.contains(c);
}
}
You could also compare the ordinal values, like so:
public enum RecordStatusEnum {
CREATED,
INSERTED,
UPDATED,
NEW,
FAILED,
FAILED_NO_DB,
FAILED_CONSTRAINT_VIOLATION;
public boolean isPersisted(RecordStatusEnum status) {
return status.ordinal < NEW.ordinal;
}
public boolean isError(RecordStatusEnum status){
return status.ordinal >= FAILED.ordinal;
}
}