【问题标题】:How to inject a static field in micronaut 2?如何在 micronaut 2 中注入静态场?
【发布时间】:2021-02-26 19:44:32
【问题描述】:

我有一个创建对象的工厂类。就我而言,这是 ObjectMapper (Jackson)。

@Factory
public class JacksonFactory {

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

}

我想将它注入到类的静态字段中:

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();
    }
  }

}

但是,它不是那样工作的。每次访问映射器静态字段时,我都会得到一个 NullPointer。如果我将方法和字段设为非静态,一切都会正常运行。

我在文档中没有找到对此的解释,可能是我遗漏了什么或者依赖注入有什么问题?

非常感谢您的帮助! :)

更新

好的,伙计们。我不是在创建静态类,而是在创建一个对象,并且我想将它作为依赖项注入到将要创建的所有对象中。为什么我创建JsonDto对象的继承者时没有注入依赖?

@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);
    }
  }

}

我以为每次创建对象时,Micronaut 都会在上下文中找到这个 bin 并替换它。但这似乎不是它的工作方式。 我完全糊涂了-_\

public abstract class JsonDto {

  @Inject
  private JsonString jsonString;

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

}

【问题讨论】:

  • 不要使用静态;这就是依赖注入的全部意义所在。使映射器(或包含它的其他服务类)成为任何需要它的构造函数参数。
  • @chrylis-cautiouslyoptimistic- 谢谢你的回答,是的,我明白你在说什么。但在这种情况下,我不想注入依赖项。我想将样板逻辑移动到静态 util 类中,并根据需要使用它。虽然这可能是一个圣战声明:)
  • 为你的“样板”使用一个单例类,并在需要的地方注入它,这就是依赖注入的目的+
  • @IEE1394 感谢您的回答,我试过了,但它不起作用 - NPE。我已经更新了帖子。

标签: java dependency-injection static micronaut


【解决方案1】:

我建议尝试类似的方法:

首先创建你的对象转换器来转换对象

@Singleton
public class ObjectConverter (private ObjectMapper mapper) {

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

}

比你的 dto 更喜欢(我更喜欢构造函数注入而不是 @inject)

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

}

最后是您的服务,负责处理 dtos

@Singleton
public class MyDtoService(private ObjectConverter mapper) {

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

}

如果我们谈论的是来自数据库的 dto,我建议类似的东西

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

public class MyDbDto implements MyJsonDbDto{

}

因此服务

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

希望对您有所帮助,对不起,我主要使用 kotlin,因此我的 java 有点生疏 ;-)

编辑:

关于您的评论,我有一个丑陋的想法,可以将其视为您重构过程的某种中间解决方案

这样创建服务(使用上下文,使其不像单例那样延迟加载)

@Context
public class MyDtoService {

  public static ObjectConverter mapper;

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

}

之后,您可以在您的 dto 中访问它

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

}

【讨论】:

  • 感谢您提供如此详细的答案,但不幸的是,在我的情况下它不起作用:*(也许我现在会澄清问题的外观:
  • Dto 来自 httpClient,我需要在其中使用服务来覆盖 toString。但是,由于我无法将服务注入到 Dto 中,因为对象不是由 DI Micronaut 创建的,所以我想将服务放入静态字段中,按照逻辑将其注入。但是,这不起作用,我将不得不通过 new 在静态字段中创建一个对象。最后内存中会有两个对象,虽然是单例。
  • 在回答中加了你一些建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-30
  • 2017-07-05
相关资源
最近更新 更多