Guice Multibinder for Annotations with Specific Value - java

I know that I can do a Guice multibind with a specific annotation as follows
Multibinder.newSetBinder(binder(), Bound.class, Annotation.class);
But can I do a more specific multibind on classes that are not only annotated with Annotation.class but also have a specific value, e.g. #Annotation("type1")?

In this case you could implement your annotation and pass an instance of it to the Multibinder static factory method:
static class YourAnnotationImpl implements YourAnnotation {
private final String value;
YourAnnotationImpl(String value) {
this.value = value;
}
#Override public String value() {
return value;
}
#Override public Class<? extends Annotation> annotationType() {
return YourAnnotation.class;
}
#Override public String toString() {
return "#" + YourAnnotation.class.getName() + "(value=" + value + ")";
}
#Override public boolean equals(Object o) {
return o instanceof YourAnnotationImpl
&& ((YourAnnotationImpl) o).value().equals(value());
}
#Override public int hashCode() {
return (127 * "value".hashCode()) ^ value.hashCode();
}
}
...
Multibinder.newSetBinder(binder(), Bound.class, new YourAnnotationImpl("type1");

Related

About Java nested Enum type

I will give the example java code for this circumstances:
// StateEntity interface define:
public interface StateEntity extends IDEntity { // the IDEntity define getId & setId
static int processBitState(int state, boolean op, int pos) {
if (op) {
state = Bits.set(state, pos);
} else {
state = Bits.clear(state, pos);
}
return state;
}
static <E extends Enum<E>, T extends StateEntity> int gatherState(Class<E> enumType, int state, #NotNull T data) {
try {
Method getJsonFieldName = enumType.getMethod("getJsonFieldName");
Method getPosition = enumType.getMethod("getPosition");
BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (E bitSet : EnumSet.allOf(enumType)) {
String fieldName = (String) getJsonFieldName.invoke(bitSet);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
if (propertyDescriptor.getName().equals(fieldName)) {
Method reader = propertyDescriptor.getReadMethod();
Boolean value = (Boolean) reader.invoke(data);
state = processBitState(state, value, (Integer) getPosition.invoke(bitSet));
break;
}
}
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | IntrospectionException e) {
e.printStackTrace();
}
return state;
}
<E extends Enum<E>> Class<E> getStateType();
Integer getState();
void setState(Integer state);
}
// Impl class:
public class StateEntityClass implements StateEntity {
Long id;
Integer state;
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#Override
public <E extends Enum<E>> Class<E> getStateType() {
return (Class<E>) (BitSet.class);
}
#Override
public Integer getState() {
return state;
}
#Override
public void setState(Integer state) {
this.state = state;
}
public enum BitSet {
ACTIVATION(0),
FREEZE(1),
UPDATE(2);
private final int position;
BitSet(int v) {
position = v;
}
#NotNull
public String getName() {
return name().toLowerCase().replaceAll("_", "-");
}
#NotNull
public String getJsonFieldName() {
return NameConverter.snakeCaseToCamelCase("is_" + name().toLowerCase());
}
public int getPosition() {
return position;
}
}
}
// used:
public class Main {
public static void main(String[] args) {
StateEntityClass e = new StateEntityClass();
// first method, this statement error:
e.setState(StateEntity.gatherState(e.getStateType(), e.getState() == null ? 0 : e.getState(), e));
// second method, but this statement ok:
e.setState(StateEntity.gatherState(StateEntityClass.BitSet.class, e.getState() == null ? 0 : e.getState(), e));
// why?? how change the first method
}
}
I have some class implements StateEntity, so I must use the first method for generic.
How do I change my code to use the first method?
What is the Java way to process these circumstances problems?
The Enum content is unrelated, the StateEntity implements class has self Enum for the state.
The problem I hope to solve is how to deal with an Enum uniformly in Java. This Enum has a unified structure and a unified interface, but the Enumerator contained is different. See the above question for the specific situation. After #tgdavies' prompt, I moved the type parameter from the method definition to the interface definition, which solved the problem. Later, under the reminder of #Guillaume F., I further optimized the use of Enum. Thank you all for participating

Return object from a list as CustomObject not just raw <T> Object

I have a CustomObject declared as raw type of <T>. And when I populate a List<CustomObject> with new instances of it, I can't get them back as a CustomObject, only as an Object.
public class CustomObject<T> {
private String name;
private T value;
// getters and setters
}
But obviously when I use subclass, all is working as expecting;
public class CustomObject {
private class SubCustomObject<T> {
private String name;
private T value;
}
public CustomObject() {
this.customObject = new SubCustomObject();
private SubCustomObject customObject;
// getters and setters
}
Is there a way to make the first example to behave like the second one, and avoid using extra object and so I could do this:
public class CustomObject<T> {
private String name;
private T value;
private boolean isGroup;
// getters and setters
private void setValue(T value) {
if (value instanceof String) {
this.value = value;
this.isGroup = false;
}
if (value instanceof CustomObject) {
if (isGroup()) {
((List<CustomObject>) this.value).add((CustomObject) value);
} else {
this.value = (T) new ArrayList<CustomObject>();
this.isGroup = true;
setValue(value);
}
}
}
}
public void getItemByName(String name) {
// say the list is already populated
for (CustomObject object : listOfCustomObject) {
String nameField = object.getName();
if (name.equals(nameField) {
System.out.println(nameField);
}
}
}
Instead of this one:
public void getItemByName(String name) {
// say the list is already populated
for (Object object : listOfCustomObject) {
String nameField = ((CustomObject)object).getName();
if (name.equals(nameField) {
System.out.println(nameField);
}
}
}
// Apply that behavior to this and avoid to use inner class.
public class MetadataEntry {
public MetadataEntry() {
this.entity = new Entry();
}
private class Entry<T> {
private String name;
private T value;
private boolean isGroup;
private void setValue(T value) {
if (value instanceof String) {
this.value = value;
this.isGroup = false;
}
if (value instanceof MetadataEntry) {
if (isGroup()) {
((List<MetadataEntry>) this.value).add((MetadataEntry) value);
} else {
this.value = (T) new ArrayList<MetadataEntry>();
this.isGroup = true;
setValue(value);
}
}
}
}
private Entry entity;
public void setName(String name) {
this.entity.name = name;
}
public String getName() {
return this.entity.name;
}
public void setValue(String value) {
entity.setValue(value);
}
public void setValue(MetadataEntry value) {
entity.setValue(value);
}
public boolean isGroup() {
return this.entity.isGroup;
}
public List<MetadataEntity> getChildNodes() {
if (isGroup()) {
return (List<MetadataEntry>) this.entity.value;
}
return null;
}
public String getValue() {
if (!isGroup()) {
return (String) this.entity.value;
}
return null;
}
}
You can not make a list of different types X,Y,Z and put it in a single container of type W. You need to define a bounding parameter on your raw type so that your items and list are of same type. probably your T should be bounded by some interface type or it should extends some class.
Here’s my suggestion. I have abandoned the generics. Instead of just one inner class there is now an abstract inner class with two subclasses, one for groups and one for entries that are not groups. The good news: no cast is necessary anywhere.
public class MetadataEntry {
private String name;
static abstract class Entry {
abstract Entry setValue(String value);
abstract Entry setValue(MetadataEntry value);
abstract boolean isGroup();
abstract List<MetadataEntry> getChildNodes();
abstract String getSimpleValue();
}
static class SimpleEntry extends Entry {
private String value;
public SimpleEntry(String value) {
this.value = value;
}
#Override
Entry setValue(String value) {
this.value = value;
return this;
}
#Override
Entry setValue(MetadataEntry value) {
return new GroupEntry(value);
}
#Override
public boolean isGroup() {
return false;
}
#Override
public List<MetadataEntry> getChildNodes() {
return null;
}
#Override
public String getSimpleValue() {
return value;
}
}
static class GroupEntry extends Entry {
List<MetadataEntry> value;
public GroupEntry(MetadataEntry value) {
this.value = new ArrayList<>();
this.value.add(value);
}
#Override
Entry setValue(String value) {
return new SimpleEntry(value);
}
#Override
Entry setValue(MetadataEntry value) {
this.value.add(value);
return this;
}
#Override
public boolean isGroup() {
return true;
}
#Override
public List<MetadataEntry> getChildNodes() {
return value;
}
#Override
public String getSimpleValue() {
return null;
}
}
private Entry entity;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setValue(String value) {
entity = entity.setValue(value);
}
public void setValue(MetadataEntry value) {
entity = entity.setValue(value);
}
public boolean isGroup() {
return this.entity.isGroup();
}
public List<MetadataEntry> getChildNodes() {
return entity.getChildNodes();
}
public String getValue() {
return entity.getSimpleValue();
}
}
I have used an idea similar to what m 1987 said about a class that returns an instance of itself. I applied it to the inner classes only to free the users of the outer class from caring about this trickery. If you prefer, I am sure it could be applied to the outer class instead. Then you would have an abstrat class on the outer level with two subclasses, and would no longer need the inner classes. This is one of the things you asked for, so you may prefer it, but it comes at a cost: anyone calling setValue() on the outer class would need to remember that they got a new instance back.
I have a CustomObject declared as raw type of <T>.
That doesn't makes sense. You either have a raw type or a generic, not a raw type of a generic.
And when I populate a List with new instances of it, I can't get them back as a CustomObject, only as an Object.
Because your list is not generic (always bad). When you declare a List<Something> it will return Something on a get call. That Something can be generic or a raw type. A List<CustomObject<String>> will not accept a CustomObject<Integer> and using the raw type List<CustomObject> will end in disaster, hence the danger in raw types.
Now let's look at your code. The class
public class CustomObject<T> {
private String name;
private T value;
}
defines an object that behaves the same for any type. In essence what you have here is just a glorified Object with a String serving as its name attached to it.
However, now you do
private void setValue(T value) {
if (value instanceof String)
// ...
if (value instanceof CustomObject)
// ...
}
which separates the behavior for different types. and what happens if the generic type is not a String or a CustomObject?
Let's try to solve your problem. Since generics are meant to unify the behavior, let's look at what the unified behavior is that you're trying to get:
public void getItemByName(String name) {
for (CustomObject object : listOfCustomObject) {
String nameField = object.getName();
// ...
}
}
}
Basically, you require that all the items in listOfCustomObject implement a String getName() method. That's it as far as I can see from your question. That means that your CustomObject<T> should either implement an interface or extend a class (call it Superthing) with that method. Then you will just declare your list as List<? extends Superthing>.
As for the CustomObject itself, it doesn't need to be generic as you hint that there are only 2 types of generics you want to deal with (you have 2 ifs, but no else to deal with a general case). It looks like what you want are 2 different classes with different behaviors that both implement or extend a common supertype.
Try something like this:
abstract class AbstractEntry {
private String name;
protected boolean isGroup;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isGroup() {
return isGroup;
}
}
class MetaEntry extends AbstractEntry {
AbstractEntry value;
MetaEntry(AbstractEntry value) {
this.value = value;
// handle isGroup
}
public void setValue(AbstractEntry value) {
this.value = value;
}
public AbstractEntry getValue() {
if (!isGroup)
return value;
return null;
}
}
class StringEntry extends AbstractEntry {
String value;
StringEntry(String value) {
this.value = value;
isGroup = false;
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
I think there is no need of list as it always hold only one element. As #Ole V.V mentioned, the requirement naturally calls for the use of composition and in fact, generic does not fit into your requirements. Here is how I would tackle your requirements:
public interface Named {
public String getName();
public String getValue();
}
public class CustomObject implements Named {
private String name;
private String value;
private boolean isGroup;
// getters and setters
private boolean isGroup() {
return isGroup;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class CustomObject2 implements Named {
private String name;
private CustomObject value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value.getValue();
}
public void setValue(CustomObject value) {
this.value = value;
}
}
public class DriverCustomObject {
public static void main(String arg[]) {
CustomObject t = new CustomObject();
t.setName("key1");
t.setValue("value1");
CustomObject2 t2 = new CustomObject2();
t2.setName("complex");
t2.setValue(t);
List<Named> list = new ArrayList<Named>();
list.add(t);
list.add(t2);
for (Named l : list) {
System.out.println(l.getName());
System.out.println(l.getValue());
}
}
}

Jackson Conditional Validation of a field

I'm trying to set up a Range Query structure on Spring with the following structure:
public class QueryRange extends Query {
#JsonProperty(required = true)
#NotBlank
#NotNull
private String field;
private Object gt;
private Object gte;
private Object lt;
private Object lte;
public String getField() {
return field;
}
public QueryRange setField(String field) {
this.field = field;
return this;
}
public Object getGt() {
return gt;
}
public QueryRange setGt(Object gt) {
this.gt = gt;
return this;
}
public Object getGte() {
return gte;
}
public QueryRange setGte(Object gte) {
this.gte = gte;
return this;
}
public Object getLt() {
return lt;
}
public QueryRange setLt(Object lt) {
this.lt = lt;
return this;
}
public Object getLte() {
return lte;
}
public QueryRange setLte(Object lte) {
this.lte = lte;
return this;
}
#AssertTrue(message = "Invalid range. A value for 'gt' or 'lt' should be set.")
private boolean isRangeSpecified() {
return this.gt != null || this.lt != null;
}
#AssertTrue(message = "Invalid range data type. 'gt' and 'lt' must be of the same type.")
private boolean isRangeDataTypeValid() {
if (this.gt != null && this.lt != null) {
return this.gt.getClass().equals(this.lt.getClass());
}
return true;
}
}
The problem is that at least one of the values gt, gte, lt or lte should be not null. How can I validate that?
I've tried Bean Validation like on the code example above, but it didn't work. Any suggestions?
You should use Class-level constraint.
Last but not least, a constraint can also be placed on the class level. In this case not a single property is subject of the validation but the complete object. Class-level constraints are useful if the validation depends on a correlation between several properties of an object.
#ValidQueryRange
public class QueryRange extends Query {
// your class here...
private Object gt;
private Object gte;
private Object lt;
private Object lte;
}
#Target({ TYPE, ANNOTATION_TYPE })
#Retention(RUNTIME)
#Constraint(validatedBy = { ValidQueryRangeValidator.class })
#Documented
public #interface ValidQueryRange {
String message() default "{error}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
public class ValidQueryRangeValidator implements ConstraintValidator<ValidQueryRange, QueryRange> {
#Override
public void initialize(ValidQueryRange constraintAnnotation) {
}
#Override
public boolean isValid(QueryRange queryRange, ConstraintValidatorContext context) {
if ( queryRange == null ) {
return true;
}
// put your logic here
if ( queryRange.getGt() == null || queryRange.getLt() == null) {
return false;
}
return true;
}
}

Two Enums implementing the same interface sharing a method

I have two Enums implementing the same interface
public interface MetaEnum{
String getDefaultValue();
String getKey();
}
public enum A implements MetaEnum{
ONE("1"), TWO("2");
private String val;
A(final v){
val = v;
}
#Override
public String getDefaultValue() {
return value;
}
#Override
public String getKey() {
return (this.getClass().getPackage().getName() + "." + this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
}
public enum B implements MetaEnum{
UN("1"), DEUX("2");
private String val;
B(final v){
val = v;
}
#Override
public String getDefaultValue() {
return value;
}
#Override
public String getKey() {
return (this.getClass().getPackage().getName() + "." + this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
...other methods specific to this enum
}
I have duplicated code and I would like to avoid it. Is there a way to implement getKey in a sort of abstract class? I looked at this question Java Enum as generic type in Enum but it cannot adapt it to what I need.
The default method from Java 8 should help you :)
This feature allows you to implement method inside an interface.
public interface MetaEnum {
String getValue();
default String getKey() {
return (this.getClass().getPackage().getName() + "." +
this.getClass().getSimpleName() + "." +
this.toString()).toLowerCase();
}
}
Unfortunately, you can't implement a default method for getters, so you still have some duplicate code.
Extract the common code to the separate class:
class MetaEnumHelper {
private String val;
MetaEnumImpl(final v){
val = v;
}
public String getDefaultValue() {
return value;
}
public String getKey(MetaEnum metaEnum) {
return (metaEnum.getClass().getPackage().getName() + "." + metaEnum.getClass().getSimpleName() + "." +
metaEnum.toString()).toLowerCase();
}
}
public enum A implements MetaEnum{
ONE("1"), TWO("2");
private MetaEnumHelper helper;
A(final v){
helper = new MetaEnumHelper(v);
}
#Override
public String getDefaultValue() {
return helper.getDefaultValue();
}
#Override
public String getKey() {
return helper.getKey(this);
}
}
public enum B implements MetaEnum{
UN("1"), DEUX("2");
private MetaEnumHelper helper;
B(final v){
helper = new MetaEnumHelper(v);
}
#Override
public String getDefaultValue() {
return helper.getDefaultValue();
}
#Override
public String getKey() {
return helper.getKey(this);
}
...other methods specific to this enum
}

com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(Object o) doesn't write a field into JSON string

I need to convert object of Student to JSON string. Object of StudentId is an attribute of Student. When I write Student to string using com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(Student s), I see all other attributes are converted to JSON string except StudentId. What do I missing StudentId class? When I debug, I do see studentId field before calling writeValueAsString(student), but somehow isn't written into JSON string.
public class StudentId extends AbstractLongId{
public StudentId(final Long id) {
super(id);
}
public StudentId(final String id) {
super(id);
}
}
public class Student {
private DateTime created;
private StudentId studentId;
private String name
}
public abstract class AbstractLongId extends AbstractId<Long> {
public AbstractLongId(final Long value) {
super(value);
}
public AbstractLongId(final String value) {
super(value);
}
#Override
protected Long fromString(final String value) {
try {
return new Long(value);
}
catch (NumberFormatException e) {
throw new IllegalArgumentException("Note valid input");
}
}
}
public abstract class AbstractId<T> extends Wrapper<T> implements Id<T> {
public AbstractId(final T value) {
super(value);
}
public AbstractId(final String value) {
super(value);
}
}
public abstract class Wrapper<T> {
private final T value;
public Wrapper(final T value) {
this.value = value;
}
public Wrapper(final String value) {
T typedValue = fromString(value);
this.value = typedValue;
}
protected abstract T fromString(final String value);
public T getValue() {
return value;
}
#Override
public String toString() {
return value.toString();
}
public boolean equalsString(final String other) {
if (other == null) {
return false;
}
return value.toString().equals(other);
}
#Override
#SuppressWarnings("unchecked")
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Wrapper)) {
return false;
}
Wrapper<T> otherId = (Wrapper<T>) other;
return value.equals(otherId.getValue());
}
#Override
public int hashCode() {
return value.hashCode();
}
}

Categories