Mr.Bere
Mr.Bere

Reputation: 35

How to inject a static field in micronaut 2?

I have a factory class that creates an object. In my case, this is ObjectMapper (Jackson).

@Factory
public class JacksonFactory {

  @Singleton
  public ObjectMapper getObjectMapper() {
    return new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
  }

}

I want to inject it into a static field of the class:

public class JsonString {

  @Inject
  private static ObjectMapper mapper;

  public static String of(Object object) {
    try {
      return mapper.writeValueAsString(object);
    } catch (JsonProcessingException exception) {
      throw new RuntimeException();
    }
  }

}

But, it doesn't work that way. I get a NullPointer every time I access the mapper static field. If I make the methods and the field non-static everything works well.

I didn’t find an explanation for this in the documentation, maybe I’m missing something or what is the problem with dependency injection?

Many thanks for the help! :)

UPDATE

Ok guys. I am not creating a static class, but creating an object and I want to inject it as a dependency into all objects that will be created. Why is the dependency not injected when I create inheritors of the JsonDto object?

@Singleton
public class JsonString {

  @Inject
  private ObjectMapper mapper;

  public String of(Object object) {
    try {
      return mapper.writeValueAsString(this);
    } catch (JsonProcessingException exception) {
      throw new KyivAirException(exception);
    }
  }

}

I thought that every time when creating an object, Micronaut will find this bin in the context and substitute it. But that doesn't seem to be how it works. I am completely confused -_\

public abstract class JsonDto {

  @Inject
  private JsonString jsonString;

  @Override
  public String toString() {
    return jsonString.of(this);
  }

}

Upvotes: 1

Views: 2147

Answers (1)

IEE1394
IEE1394

Reputation: 1261

i suggest try something like that:

First create your object converter which will take of converting the objects

@Singleton
public class ObjectConverter (private ObjectMapper mapper) {

  public String of(Object object) {
    try {
      return mapper.writeValueAsString(this);
    } catch (JsonProcessingException exception) {
      throw new RuntimeException(exception);
    }
  }

}

Than have your dto like that (i prefer constructor injection over @inject)

public abstract class MyDto(private ObjectConverter converter)  {
    
  @Override
  public String toString() {
    return converter.of(this);
  }

}

And finally your service, taking care of the dtos

@Singleton
public class MyDtoService(private ObjectConverter mapper) {

  public String get(Long id) {
  // TODO get the object from somewhere
  return mapper.of(dto)
  }

}

If we are talking about a dto that comes from the database i suggest something like that

interface MyJsonDbDto {
   String decode(ObjectConverter mapper) {
     return mapper.of(this)
   }
}

public class MyDbDto implements MyJsonDbDto{

}

and the service therefore

public class MyDbDtoService(private ObjectConverter converter, private MyDbDtoRepository repository)
      public String get(Long id) {
  // TODO get the object from repository
  return dto.decode(converter)
  }
}

hope that helps and sorry i am mainly in kotlin, therefore my java is a little rusty ;-)

EDIT:

regarding your comment, i have an ugly idea, which could be considered as a some kind of intermediate solution for your refactoring process

create the service like that (use context, cause its not lazy loaded like a singleton)

@Context
public class MyDtoService {

  public static ObjectConverter mapper;

  public MyDtoService(ObjectConverter mapper) {
     MyDtoService.mapper = mapper;
  }

}

after that you can access it whithin your dto

public class MyDto {
    
  @Override
  public String toString() {
    return MyDtoService.mapper.of(this);
  }

}

Upvotes: 3

Related Questions