I have an annotation
public #interface Field {
String value();
}
and java class, annotated by it:
public class Animal {
#Field("name")
private String name;
}
I try to list all field' annotations by the next code:
for(field in clazz.declaredFields){
for(annotation in field.annotations){
when(annotation){
is Field -> {
//do something
}
}
}
}
where clazz is Class<T>
but field.annotations is empty.
How to list annotations correctly?
Java annotations, by default, are not retained at runtime so you'll need to specify such:
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Retention(RUNTIME)
public #interface Field {
String value();
}
Kotlin annotations are retained by default:
annotation class Field(val value: String)
The issue isn't Kotlin specific, you just haven't configured Field annotation properly. By default, each annotation is retained with RetentionPolicy.CLASS, meaning it won't be accessible via reflection. You have to use RetentionPolicy.RUNTIME if you want to access the annotation in the runtime.
#Retention(RetentionPolicy.RUNTIME)
public #interface Field {
String value();
}
Related
Single interface: IDoSomething {...}
Two classes implement that interface:
ClassA : IDoSomething {...}
ClassB : IDoSomething {...}
One class uses any of those classes.
public class DummyClass(IDoSomething doSomething) {...}
code without Autofac:
{
....
IDoSomething myProperty;
if (type == "A")
myProperty = new DummyClass (new ClassA());
else
myProperty = new DummyClass (new ClassB());
myProperty.CallSomeMethod();
....
}
Is it possible to implement something like that using Autofac?
Thanks in advance,
What you are looking for is, as I remember, the Strategy Pattern. You may have N implementations of a single interface. As long you register them all, Autofac or any other DI framework should provide them all.
One of the options would be to create a declaration of the property with private setter or only getter inside Interface then implement that property in each of the class. In the class where you need to select the correct implementation, the constructor should have the parameter IEnumerable<ICommon>.
Autofac or any other DI frameworks should inject all possible implementation. After that, you could spin foreach and search for the desired property.
It may look something like this.
public interface ICommon{
string Identifier{get;}
void commonAction();
}
public class A: ICommon{
public string Identifier { get{return "ClassA";} }
public void commonAction()
{
Console.WriteLine("ClassA");
}
}
public class A: ICommon{
public string Identifier { get{return "ClassB";} }
public void commonAction()
{
Console.WriteLine("ClassA");
}
}
public class Action{
private IEnumerable<ICommon> _common;
public Action(IEnumerable<ICommon> common){
_common = common;
}
public void SelectorMethod(){
foreach(var classes in _common){
if(classes.Identifier == "ClassA"){
classes.commonAction();
}
}
}
}
I am trying to create a way to serialize and deserialize objects to JSON using Jackson without having to rely on annotations, mix-ins or any code that is object-specific (ie: specific deserializers). However, I'm having trouble deserializing interfaces.
An idea that I had was to store the class name of the object within the JSON. For instance, if I have the following classes:
MyClassOne.java
package test.classes;
public class MyClassOne{
private String myString;
private MyClass myReference;
public MyClassOne(String myString, MyClass myReference) {
this.myString = myString;
this.myReference = myReference;
}
public String getMyString() {
return myString;
}
public MyClass getMyReference() {
return myReference;
}
}
MyClassTwo.java
package test.classes;
public class MyClassTwo implements MyClass{
private int myInt;
public MyClassTwo(int myInt) {
this.myInt = myInt;
}
public int getMyInt() {
return myInt;
}
}
I would like to use Jackson to serialize MyObjectOne instances into something similar to:
{
"_class":"test.classes.MyClassOne" ,
"myString":"Hello World",
"myReference":{
"_class":"test.classes.MyClassTwo",
"myInt":2
}
}
I was wondering if that could work and how to accomplish it with Jackson.
An idea that I had was to store the class name of the object within the JSON.
You could consider enableDefaultTypingAsProperty() for automatic inclusion of type information:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, "_class");
I am trying to create a way to serialize and deserialize objects to JSON using Jackson without having to rely on annotations, mix-ins or any code that is object-specific (ie: specific deserializers).
Consider the following code using the types defined in your own question:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL, "_class");
MyClass myClass = new MyClassTwo(2);
MyClassOne myClassOne = new MyClassOne("Hello World", myClass);
String json = mapper.writer()
.withDefaultPrettyPrinter()
.writeValueAsString(myClassOne);
It will produce the following JSON:
{
"_class" : "com.example.examples.foo.MyClassOne",
"myString" : "Hello World",
"myReference" : {
"_class" : "com.example.examples.foo.MyClassTwo",
"myInt" : 2
}
}
To deserialize the above JSON, however, your classes must have a default constructor (or use #JsonCreator).
Currently I am trying to reduce the boilerplate in my java spring controllers by creating an interface CRUDRestController, which creates a common set of default endpoints:
interface CRUDRestController<T, Key extends Serializable> {
//...
String getEndpoint();
#RequestMapping(value = getEndpoint() + "/{key}", method = RequestMethod.GET)
default T get(#PathVariable("key") String key) {
return getRepository().findOne(stringToKey(key));
}
//...
}
The problem is that the above code does not compile since value = getEndpoint() + "/{key}" is supposedly not a compile time constant. In reality every controller's implementation of getEndpoint() is something like this:
#Override
public String getEndpoint() {
return "/clients";
}
This is clearly known at compile time, however I have no way of telling this to spring. Any ideas?
Maybe that will help you:
interface CRUDRestController<T, Key extends Serializable> {
#RequestMapping(value = "/{key}", method = RequestMethod.GET)
default T get(#PathVariable("key") String key) {
return getRepository().findOne(stringToKey(key));
}
}
and the implementation:
#RequestMapping("/clients")
public class ClientController implements CRUDRestController<Client, ClientKey> {
//...
}
This is a Java annotations restriction. All values passed to it must be compile time constants.
The value is clearly not known at compile time even if you would call a static method returning a static final.
I'm new to Jersey 2 and JAX-RS, so probably I'm missing something.
What I'm trying to do is a test program to define a coding style in rest services developing.
The test was written in JAVA and uses JERSEY 2.22.2, JDK 1.8.31, MOXY AS JSON Provider.
I defined a Resource with GET methods to support LIST/DETAIL. Due to the size of my POJO, I used some filters and everything was fine.
// 1) First of all I defined the annotation.
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#EntityFiltering
public #interface MyDetailView {
public static class Factory extends AnnotationLiteral<MyDetailView>
implements MyDetailView {
private Factory() {
}
public static MyDetailView get() {
return new Factory();
}
}
// 2) Once defined the annotation, I used to
// programmaticaly exclude the list of subItems in the response...
#XmlRootElement
public class MyPojo {
...
//*** THIS SHOULD BE FILTERED IF THE ANNOTATION IS NOT SPECIFIED IN THE RESPONSE ***
#MyDetailView
private List<SubItem> subItems = new ArrayList<SubItem>();
public List<SubItem> getSubItems() {
return subItems;
}
public void setSubItems(List<SubItem> subItems) {
this.subItems = subItems;
}
}
// 3) I registered the EntityFilteringFeature
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
}
// 4) Finally, I wrote the code to include/exclude the subItems
/*
The Resource class has getCollection() and getItem() methods...
getCollection() adds the annotation only if filterStyle="detail"
getItem() always add the annotation
*/
#Path(....)
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class MyResource extends SecuredResource {
//filterStyle -> "detail" means MyDetailAnnotation
#GET
public Response getCollection(
#QueryParam("filterStyle") String filterStyle,
#Context UriInfo uriInfo) {
//THIS CODE AFFECTS THE RESPONSE
boolean detailedResponse = "detail".equals(filterStyle);
Annotation[] responseAnnotations = detailedResponse
? new Annotation[0]
: new Annotation[]{MyDetailView.Factory.get()};
//pojo collection...
MyPagedCollection myCollection = new MyPagedCollection();
//.....
ResponseBuilder builder = Response.ok();
return builder.entity(myCollection, responseAnnotations).build();
}
#GET
#Path("/{id}")
public Response getItem(#PathParam("{id}") String idS, #Context UriInfo uriInfo) {
MyPOJO pojo = ...
Annotation[] responseAnnotations = new Annotation[]{MyDetailView.Factory.get()};
return Response.ok().entity(pojo, responseAnnotations).build();
}
}
After the first test, I tried to use the SelectableEntityFilteringFeature to allow the client to ask for specific fields in the detail, so I changed the ApplicationConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
register(SelectableEntityFilteringFeature.class);
property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
and I've add the "fields" QueryParam to the Resource getItem() method...
#GET
#Path("/{id}")
public Response getDetail(#PathParam({id}) String id,
#QueryParam("fields") String fields,
#Context UriInfo uriInfo) {
....
But as long as I registered the SelectableEntityFilteringFeature class, the EntityFilteringFeature class stopped working. I tried to add "fields" parameter to one of the Resource methods, it worked perfectly. But the MyDetailAnnotation was completely useless.
I tried to register it using a DynamicFeature
public class MyDynamicFeature implements DynamicFeature {
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if ("MyResource".equals(resourceInfo.getResourceClass().getSimpleName())
&& "getItem".equals(resourceInfo.getResourceMethod().getName())) {
//*** IS THE CORRECT WAY TO BIND A FEATURE TO A METHOD? ***
//
context.register(SelectableEntityFilteringFeature.class);
context.property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
}
Now the questions:
1) Why registering both the SelectableEntityFilteringFeature feature breaks the EntityFilteringFeature?
2) What is the correct way to bind a feature to a method with the DynamicFeature interface?
Thanks in advance.
This is my first post to Stack Overflow, I hope it was written complaining the rules.
Short answer: you can't. It appears to be a bug as of 2.25.1 and up to 2.26(that I tested with). https://github.com/jersey/jersey/issues/3523
SelectableEntityFilteringFeature implictily registers EntityFilteringFeature (As mentioned here). So I don't see a need to add this.
Since you need Annotation based filtering, you can exclude registering SelectableEntityFilteringFeature.
You can just do,
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {MyDetailView.Factory.get()})
// Register the EntityFilteringFeature.
.register(EntityFilteringFeature.class)
// Further configuration of ResourceConfig.
You can refer to this example for usage and this example for registering the filter.
So you can remove SelectableEntityFilteringFeature and try just the above mentioned way to register it.
I am trying to send over MyClass through RPC, but am getting :
Type MyClass was not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' and did not have a custom field serializer.For security purposes, this type will not be serialized.
I have looked at GWT - occasional com.google.gwt.user.client.rpc.SerializationException and tried their solution, but it did not work.
The difference is that MyClass is located in another project.
The project structure is:
MyApiProject
-contains MyClass
MyClientProject
MyServerProject
I have also tried passing an enum through the RPC from MyApiProject, which also failed.
public class MyClass
implements Serializable
{
private static final long serialVersionUID = 5258129039653904120L;
private String str;
private MyClass()
{
}
public MyClass(String str)
{
this.str = str;
}
public String getString()
{
return this.str;
}
}
in the RemoteService I have:
mypackage.MyClass getMyClass();
in the RemoteServiceAsync I have:
void getMyClass(AsyncCallback<mypackage.MyClass> callback);
I had to change implements Serializable to implements IsSerializable
This usually pops up when you are using another type inside of your class that is not serializable. Check the properties of your class and make sure they are all serializable, post the code of MyClass here and I can look at it as well.
I believe GWT requires an RPC serializable class to also have a public no-argument constructor.
Try removing
private MyClass()
{
}
or set it to
public MyClass()
{
}