I create XML with JAXB, and I want to put double inside tags:
#XmlElement(name = "TaxFree")
private double taxFreeValue;
When I set value with setTaxFreeValue(4.5); in tags shows <TaxFree>4.5<TaxFree>
Is it possible in JAXB to get this <TaxFree>4.500<TaxFree> without transfer double to string?
The simplest way is this
double taxFreeValue;
#XmlElement(name = "TaxFree")
private String getTaxFree() {
return String.format("%.3f", taxFreeValue);
}
Note that you can give this method any name and make it private JAXB dont care as soon as the annotation is present.
You can use an XmlAdapter to convert from the double value to the desired text (String) representation.
Using JAXB generated class for an element that requires an integer with a pattern
The cleanest way I've found is to use XMLAdapter. Create a DoubleAdapter class with:
public class DoubleAdapter extends XmlAdapter<String, Double> {
#Override
public Double unmarshal(String v) throws Exception {
if (v == null || v.isEmpty() || v.equals("null")) {
return null;
}
return Double.parseDouble(v);
}
#Override
public String marshal(Double v) throws Exception {
if (v == null) {
return null;
}
//Edit the format to your needs
return String.format("%.3f", v);
}
}
To use it, simply add the annotation.
#XmlElement(name = "TaxFree")
#XmlJavaTypeAdapter(DoubleAdapter.class)
private double taxFreeValue;
Related
I tried to create a float field in Vaadin from String field (I dont know any other method ;)
I have a validation which should allow me that a String field will be just a float field. I found only a solution for an integer? How to asure that my user can type only float number?
#Override
public void setConfiguration(EditorConfiguration editorConfiguration) {
Validator<String> validator = ((FloatFieldConfiguration) editorConfiguration).getValidator();
if (validator != null) {
binder.forField(this).withValidator(validator)
.withConverter(new StringToFloatConverter("Must enter a number"))
.bind(s -> getValue(), (b, v) -> setValue(v));
}
}
There can be various ways to achieve your purpose but I would recommend you to use the custom converter by implementing the Converter Interface.
Here is something that you can try:
class CustomConverter implements Converter<String, Double> {
#Override
public Result<Double> convertToModel(String fieldValue, ValueContext context) {
// Produces a converted value or an error
try {
// ok is a static helper method that creates a Result
return Result.ok(Double.valueOf(fieldValue));
} catch (NumberFormatException e) {
// error is a static helper method that creates a Result
return Result.error("Please enter a decimal value");
}
}
//for business object
#Override
public String convertToPresentation(Double dbl, ValueContext context)
{
// Converting to the field type should always succeed,
// so there is no support for returning an error Result.
return String.valueOf(dbl);
}
}
After that you can simply call CustomConverter inside the withConverter() method.(like .withConverter(new CustomConverter()).bind()). This is the ideal way to define your conversions(if you want something exactly as you wish.)
Hope it serves your purpose..:)
Is it possible to allow multiple #QueryParam keys for a single object/variable in Jersey?
Actual:
#POST
public Something getThings(#QueryParam("customer-number") Integer n) {
...
}
so, if I add ?customer-number=3 after the URL it works.
Expected:
I want to get the behavior above if I add any of the following values:
?customer-number=3
?customerNumber=3
?customerNo=3
Obs:
The QueryParam annotation looks like:
...
public #interface QueryParam {
String value();
}
so, it cannot accept multiple String values (like #Produces).
The approach below allows the user to use multiple keys having the same meaning at the same time (and I want to have an "OR" condition between them):
#POST
public Something getThings(#QueryParam("customer-number") Integer n1,
#QueryParam("customerNumber") Integer n2,
#QueryParam("customerNo") Integer n3) {
...
}
Something like this doesn't work:
#POST
public Something getThings(#QueryParam("customer-number|customerNumber|customerNo") Integer n) {
...
}
How can I do this?
Details:
Jersey 2.22.1
Java 8
To be honest: this is not how webservices are supposed to be designed. You lay down a strict contract that both client and server follow; you define one parameter and that's it.
But of course it would be a perfect world where you have the freedom to dictate what is going to happen. So if you must allow three parameters in, then you'll have to make that the contract. This is one way following approach #2 which I have to provide without being able to test it for goofs:
public Something getThings(#QueryParam("customer-number") Integer n1,
#QueryParam("customerNumber") Integer n2,
#QueryParam("customerNo") Integer n3) throws YourFailureException {
Integer customerNumber = getNonNullValue("Customer number", n1, n2, n3);
// things with stuff
}
private static Integer getNonNullValue(String label, Integer... params) throws YourFailureException {
Integer value = null;
for(Integer choice : params){
if(choice != null){
if(value != null){
// this means there are at least two query parameters passed with a value
throw new YourFailureException("Ambiguous " + label + " parameters");
}
value = choice;
}
}
if(value == null){
throw new YourFailureException("Missing " + label + " parameter");
}
return value;
}
So basically reject any call that does not pass specifically one of the parameters, and let an exception mapper translate the exception you throw into a HTTP response code in the 4xx range of course.
(I made the getNonNullValue() method static is it strikes me as a reusable utility function).
Maybe the simplest and easiest way would be to use a custom #BeanParam:
First define the custom bean merging all the query parameters as:
class MergedIntegerValue {
private final Integer value;
public MergedIntegerValue(
#QueryParam("n1") Integer n1,
#QueryParam("n2") Integer n2,
#QueryParam("n3") Integer n3) {
this.value = n1 != null ? n1
: n2 != null ? n2
: n3 != null ? n3
: null;
// Throw an exception if value == null ?
}
public Integer getValue() {
return value;
}
}
and then use it with #BeanParam in your resource method:
public Something getThings(
#BeanParam MergedIntegerValue n) {
// Use n.getValue() ...
}
Reference: https://jersey.java.net/documentation/latest/user-guide.html#d0e2403
You can create a custom annotation. I won't go in too much about how to do it, you can see this post, or this post. Basically it relies on a different infrastructure than the usual dependency injection with Jersey. You can see this package from the Jersey project. This is where all the injection providers live that handle the #XxxParam injections. If you examine the source code, you will see the the implementations are fairly the same. The two links I provided above follow the same pattern, as well as the code below.
What I did was created a custom annotation
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface VaryingParam {
String value();
#SuppressWarnings("AnnotationAsSuperInterface")
public static class Factory
extends AnnotationLiteral<VaryingParam> implements VaryingParam {
private final String value;
public static VaryingParam create(final String newValue) {
return new Factory(newValue);
}
public Factory(String newValue) {
this.value = newValue;
}
#Override
public String value() {
return this.value;
}
}
}
It may seem odd that I have a factory to create it, but this was required for the implementation of the below code, where I split the value of the String, and end up creating a new annotation instance for each split value.
Here is the ValueFactoryProvider (which, if you've read either of the above articles, you will see that is required for custom method parameter injection). It a large class, only because I put all the required classes into a single class, following the pattern you see in the Jersey project.
public class VaryingParamValueFactoryProvider extends AbstractValueFactoryProvider {
#Inject
public VaryingParamValueFactoryProvider(
final MultivaluedParameterExtractorProvider mpep,
final ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
#Override
protected Factory<?> createValueFactory(final Parameter parameter) {
VaryingParam annotation = parameter.getAnnotation(VaryingParam.class);
if (annotation == null) {
return null;
}
String value = annotation.value();
if (value == null || value.length() == 0) {
return null;
}
String[] variations = value.split("\\s*\\|\\s*");
return new VaryingParamFactory(variations, parameter);
}
private static Parameter cloneParameter(final Parameter original, final String value) {
Annotation[] annotations = changeVaryingParam(original.getAnnotations(), value);
Parameter clone = Parameter.create(
original.getRawType(),
original.getRawType(),
true,
original.getRawType(),
original.getRawType(),
annotations);
return clone;
}
private static Annotation[] changeVaryingParam(final Annotation[] annos, final String value) {
for (int i = 0; i < annos.length; i++) {
if (annos[i] instanceof VaryingParam) {
annos[i] = VaryingParam.Factory.create(value);
break;
}
}
return annos;
}
private class VaryingParamFactory extends AbstractContainerRequestValueFactory<Object> {
private final String[] variations;
private final Parameter parameter;
private final boolean decode;
private final Class<?> paramType;
private final boolean isList;
private final boolean isSet;
VaryingParamFactory(final String[] variations, final Parameter parameter) {
this.variations = variations;
this.parameter = parameter;
this.decode = !parameter.isEncoded();
this.paramType = parameter.getRawType();
this.isList = paramType == List.class;
this.isSet = paramType == Set.class;
}
#Override
public Object provide() {
MultivaluedParameterExtractor<?> e = null;
try {
Object value = null;
MultivaluedMap<String, String> params
= getContainerRequest().getUriInfo().getQueryParameters(decode);
for (String variant : variations) {
e = get(cloneParameter(parameter, variant));
if (e == null) {
return null;
}
if (isList) {
List list = (List<?>) e.extract(params);
if (value == null) {
value = new ArrayList();
}
((List<?>) value).addAll(list);
} else if (isSet) {
Set set = (Set<?>) e.extract(params);
if (value == null) {
value = new HashSet();
}
((Set<?>) value).addAll(set);
} else {
value = e.extract(params);
if (value != null) {
return value;
}
}
}
return value;
} catch (ExtractorException ex) {
if (e == null) {
throw new ParamException.QueryParamException(ex.getCause(),
parameter.getSourceName(), parameter.getDefaultValue());
} else {
throw new ParamException.QueryParamException(ex.getCause(),
e.getName(), e.getDefaultValueString());
}
}
}
}
private static class Resolver extends ParamInjectionResolver<VaryingParam> {
public Resolver() {
super(VaryingParamValueFactoryProvider.class);
}
}
public static class Binder extends AbstractBinder {
#Override
protected void configure() {
bind(VaryingParamValueFactoryProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
bind(VaryingParamValueFactoryProvider.Resolver.class)
.to(new TypeLiteral<InjectionResolver<VaryingParam>>() {
})
.in(Singleton.class);
}
}
}
You will need to register this class' Binder (bottom of class) with Jersey to use it.
What differentiates this class from Jersey QueryParamValueFactoryProvider is that instead of just processing a single String value of the annotation, it splits the value, and tries to extract the values from the query param map. The first value found will be returned. If the parameter is a List or Set, it just continues to keep looking up all the options, and adding them to the list.
For the most part this keeps all the functionality you would expect from an #XxxParam annotation. The only thing that was difficult to implement (so I left out supporting this use case), is multiple parameters, e.g.
#GET
#Path("multiple")
public String getMultipleVariants(#VaryingParam("param-1|param-2|param-3") String value1,
#VaryingParam("param-1|param-2|param-3") String value2) {
return value1 + ":" + value2;
}
I actually don't think it should be that hard to implement, if you really need it, it's just a matter of creating a new MultivaluedMap, removing a value if it is found. This would be implemented in the provide() method of the VaryingParamFactory above. If you need this use case, you could just use a List or Set instead.
See this GitHub Gist (it's rather long) for a complete test case, using Jersey Test Framework. You can see all the use cases I tested in the QueryTestResource, and where I register the Binder with the ResourceConfig in the test configure() method.
I have a requirement, where I need to convert String into double or long.
the field on which I have applied #TypeConvertor can also contains String sometimes.
As it can be seen in below snippet, isNumber property is true when I get a number.
is there anyway I can pass isNumber to Struts2 type convertor? or any other workaround for this ?
Class XYZ{
private boolean isNumber;
private String value;
#TypeConvertor
public void setValue(){
}
}
Struts2 implicitly performs a basic type conversion to a known types, double and long are these types. So, you don't need a convertor to convert these types. But if you need a custom implementation of the type converter you may try
The action:
private Double doubleValue;
public Double getDoubleValue() {
return doubleValue;
}
#TypeConversion(converter = "com.struts.conversion.DoubleConverter")
public void setDoubleValue(Double doubleValue) {
this.doubleValue = doubleValue;
}
DoubleConverter.java:
public class DoubleConverter extends StrutsTypeConverter {
#Override
public Object convertFromString(Map context, String[] values, Class toClass) {
Object o = null;
try {
o = Double.valueOf(values[0]);
} catch (NumberFormatException e){}
return o;
}
#Override
public String convertToString(Map context, Object o) {
return o==null?"":o.toString();
}
}
The #TypeConversion annotation is to a property which type is converted. I have applied it on property of type Double, but you may try to apply your converter on property of type XYZ like
#TypeConversion(converter = "com.struts.conversion.YourNumberConverter")
public void setValue(XYZ value) {
this.value = value;
}
When converter is invoked you should get all values as String[] including isNumber and value.
i am trying to map String to enum Object using Jackson ObjectMapper.readValue(String,Class) API, problem is Lets SAY my json string contains a Task Object with Action enum as below
public enum Action {
#XmlEnumValue("Add")
ADD("Add"),
#XmlEnumValue("Amend")
AMEND("Amend"),
#XmlEnumValue("Delete")
DELETE("Delete"),
#XmlEnumValue("Pending")
PENDING("Pending");
private final String value;
Action(String v) {
value = v;
}
public String value() {
return value;
}
public static Action fromValue(String v) {
for (Action c: Action.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}
}
and the jason string will be like this "{"action":"Add"}" then ObjectMapper.readValue(jsonString, Task.Class) throws
org.codehaus.jackson.map.deser.StdDeserializationContext.weirdStringException(StdDeserializationContext.java:243) for Action Add because it cant convert this Enum.
I tried adding custom Desiserializer, But EnumDeserializer getting called anyway. any ideas?
All objects are JAXB generated, so annotations not possible.
Thanks for the help
Have you tried:
new ObjectMapper().setAnnotationIntrospector(new JaxbAnnotationIntrospector()).readValue()
Can I write a generic method to trim all strings within an complex object (object containing other objects)? Should java reflection api be used to achieve this?Thanks.
I have provided a sample below. However in reality there could be multiple objects within objects. Each object might contain a collection of String or collection of other objects which may contain String. Is there a way to trim the Strings - ones directly with the objects and ones within collection.
public class School{
private List<Course> courses;
private List<Student> students;
// Getters and Setters
}
public class Course{
private String name;
private String xxx;
private String yyy;
private List<String> zzzList;
}
public class Student{
private Map<String,String> xxx;
private List<Course> courseList;
}
Yes, reflection is the way. Basically, you need to:
get the class of the top level object (with [object].getClass())
get all the fields of the object (with clazz.getFields() - beware, it works only with public fields)
check if the field is String (either get field.getType() and check it's a string, or do a field.get(the object) and a instanceof String)
if it's the case, replace the string in the object with the trimmed one, using field.set([your object],[trimmed string])
if the field is an object but not a string, call your method recursively
That will do the trick.
---- just seen your update
Trimming strings in collection will be more tricky, since the strings are not exposed as public fields of the collection (List for example).
You will need something more clever, that will check if an object is an instance of List, or Map, or etc... (or a derived class!).
Main problem is also that java generics are done with erasing type at compile type. So you cannot know that your field is List[String] or List[Integer] or whatever. Every List[?] becomes List.
Still you can try to do it like that:
if field type is List
iterate through the list values
if a value is instanceof String, you have to remove it from the list and insert in place the trimmed version
if a value is an object, there you go again recursively with your method.
Not very interesting in real life samples, but more on a library side maybe.
Long way to go though!
Yes, you can do that with reflection, quite easily. Just check if the field is instanceof String.
The exact way to do it depends on your object structure.
/*********************************************************************************************
* Trim first level children of string type in this object
* #param obj which all string properties to be trimmed
*********************************************************************************************/
public static void trimAll(final Object obj)
throws LocalException
{
if (obj==null) return;
final Class c = obj.getClass();
final Method[] methods = c.getMethods();
final Class[] SETTER_ARGS = new Class[]{String.class};
final Object[] SETTER_VAL = new Object[1];
final String SET = "set";
final String GET = "get";
final String SPACE = "\u0020";
final String TAB = "\t";
for (final Method m:methods)
{
try
{
final String name=m.getName();
if (
name.length()>GET.length()
&& name.indexOf(GET)==0
&& m.getReturnType().equals(String.class)
&& m.getParameterTypes().length==0)
{
final String v = (String)m.invoke(obj);
if (v!=null && (v.contains(SPACE) || v.contains(TAB)) )
{
final Method setter=c.getMethod(SET+name.substring(3),SETTER_ARGS);
if (setter!=null)
{
SETTER_VAL[0]=v.trim();
setter.invoke(obj,SETTER_VAL);
}
}
}
}
catch (final Throwable e)
{
throw new LocalException(LocalException.EC_GENERAL_EXCEPTION,e);
}
}
}
We can also use Jackson to serialize and then deserialize the object. While deserializing we can use custom deserializer to trim all the String values.
Create a deserializer like this:
public class TrimStringToNullDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
String value = jsonParser.getValueAsString();
if (isNull(value)) {
return null;
}
value = value.trim();
if (value.length() == 0) {
value = null;
}
return value;
}
And then we can use Jackson to trim all values:
public class TrimStringToNullConfiguration {
private ObjectMapper objectMapper;
public Client trimToNull(Client inputClient) throws JsonProcessingException {
return getObjectMapper().readValue(getObjectMapper().writeValueAsString(inputClient), Client.class);
}
private ObjectMapper getObjectMapper() {
if (isNull(objectMapper)) {
objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new TrimStringToNullDeserializer());
objectMapper.registerModule(module);
}
return objectMapper;
}
I have placed a working example over here.
private <T> T toTrim(T t) {
Field[] fields = t.getClass().getFields();
for (Field field : fields) {
try {
if (field.get(t) instanceof String) {
Object o = field.get(t);
String s = (String) o;
field.set(t, s.trim().toUpperCase());
}
} catch (IllegalAccessException e) {
log.info("Error converting field "+ field.getName() );
}
}
return t;
}
if (yourObject instanceof String){
yourObject = yourObject.trim();
}
Hope it helps :)