Java GWT Maven插件:在Messages类中生成非字符串参数

Java GWT Maven插件:在Messages类中生成非字符串参数,java,gwt,maven,Java,Gwt,Maven,我的“Messages.properties”文件中有一个属性,该属性的参数使用数字格式: my.message=File exceeds {0,number,0.0}MB. 当我运行gwt:i18nMaven目标时,它会根据“Messages.properties”文件中的属性生成一个Messages接口(与正常情况类似): 问题是方法参数是字符串。当我运行应用程序时,它会给我一个错误,因为message参数需要一个数字,但提供了一个字符串(错误消息是,“只有number子类可以格式化为数字

我的“Messages.properties”文件中有一个属性,该属性的参数使用数字格式:

my.message=File exceeds {0,number,0.0}MB.
当我运行
gwt:i18n
Maven目标时,它会根据“Messages.properties”文件中的属性生成一个
Messages
接口(与正常情况类似):

问题是方法参数是
字符串
。当我运行应用程序时,它会给我一个错误,因为message参数需要一个数字,但提供了一个字符串(错误消息是,“只有number子类可以格式化为数字”)


如何配置Maven使其将此参数更改为数字(如
浮点
数字
)?谢谢。

在我看来,GWT I18NCreator不支持此功能(maven i18n目标就是这么称呼的)。要做到这一点,您必须编写自己的生成器。 我已经写了几个生成器,并没有你想象的那么难。 在您的情况下,您可能希望编写一个生成器,创建一个类似于GWT消息的接口实例(但您可以使用自己的实例),但它具有解码消息时所需的附加功能。 以下操作指南可能会对您有所帮助,因为它似乎与我所做的差不多,而且很有效:

我发现编写GWT生成器最简单的方法是使用您希望在IDE中生成的代码(并借助自动完成、语法检查等)编写一个测试类,然后通过/调整它以适应编写器调用,如下所示:

writer.println("public void doSomething() { /* implement */ }");
<generate-with  class="mycompany.utils.generators.MyGenerator">
    <when-type-assignable class="mycompany.messages.MyCoolPropertiesReader" />
</generate-with>
public class TestGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
  String typeName) throws UnableToCompleteException {
  try {
    TypeOracle oracle = context.getTypeOracle();
    JClassType requestedClass = oracle.getType(typeName);
    String packageName = requestedClass.getPackage().getName();
    String simpleClassName = requestedClass.getSimpleSourceName();
    String proxyClassName = simpleClassName + "GetterAndSetter";
    String qualifiedProxyClassName = packageName + "." + proxyClassName;
    System.out.println("Created a class called: " + qualifiedProxyClassName);

    PrintWriter printWriter = context.tryCreate(logger, packageName, className);
    if (printWriter == null) return null;
      ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, className);
      composerFactory.addImport("test.project.shared.GetterAndSetter");
      composerFactory.addImplementedInterface("GetterAndSetter<" + underlyingTypeName + ">");
      SourceWriter writer = composerFactory.createSourceWriter(context, printWriter);
      if (writer != null) {
        JField[] fields = requestedClass.getFields();
        for (JField field : fields) {
          createSetterMethodForField(typeName, writer, field);
        }
        writer.indent();
        writer.println("public void set(" + typeName + " target, String path, Object value) {");
        writer.indent();
        createIfBlockForFields(writer, fields, true);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.println("public <K> K get(" + typeName + " target, String path) {");
        writer.indent();
        createIfBlockForFields(writer, fields, false);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.outdent();
        writer.commit(logger);
      }
      return packageName + "." + proxyClassName;
    } catch(NotFoundException nfe) {
      throw new UnableToCompleteException();
    }
  }
}
不要忘记告诉您的模块(module.gwt.xml文件)需要生成哪个接口,以及使用哪个类,如下所示:

writer.println("public void doSomething() { /* implement */ }");
<generate-with  class="mycompany.utils.generators.MyGenerator">
    <when-type-assignable class="mycompany.messages.MyCoolPropertiesReader" />
</generate-with>
public class TestGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
  String typeName) throws UnableToCompleteException {
  try {
    TypeOracle oracle = context.getTypeOracle();
    JClassType requestedClass = oracle.getType(typeName);
    String packageName = requestedClass.getPackage().getName();
    String simpleClassName = requestedClass.getSimpleSourceName();
    String proxyClassName = simpleClassName + "GetterAndSetter";
    String qualifiedProxyClassName = packageName + "." + proxyClassName;
    System.out.println("Created a class called: " + qualifiedProxyClassName);

    PrintWriter printWriter = context.tryCreate(logger, packageName, className);
    if (printWriter == null) return null;
      ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, className);
      composerFactory.addImport("test.project.shared.GetterAndSetter");
      composerFactory.addImplementedInterface("GetterAndSetter<" + underlyingTypeName + ">");
      SourceWriter writer = composerFactory.createSourceWriter(context, printWriter);
      if (writer != null) {
        JField[] fields = requestedClass.getFields();
        for (JField field : fields) {
          createSetterMethodForField(typeName, writer, field);
        }
        writer.indent();
        writer.println("public void set(" + typeName + " target, String path, Object value) {");
        writer.indent();
        createIfBlockForFields(writer, fields, true);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.println("public <K> K get(" + typeName + " target, String path) {");
        writer.indent();
        createIfBlockForFields(writer, fields, false);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.outdent();
        writer.commit(logger);
      }
      return packageName + "." + proxyClassName;
    } catch(NotFoundException nfe) {
      throw new UnableToCompleteException();
    }
  }
}
我编写的测试生成器(GWT“反射式”getter和setter)如下所示:

writer.println("public void doSomething() { /* implement */ }");
<generate-with  class="mycompany.utils.generators.MyGenerator">
    <when-type-assignable class="mycompany.messages.MyCoolPropertiesReader" />
</generate-with>
public class TestGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
  String typeName) throws UnableToCompleteException {
  try {
    TypeOracle oracle = context.getTypeOracle();
    JClassType requestedClass = oracle.getType(typeName);
    String packageName = requestedClass.getPackage().getName();
    String simpleClassName = requestedClass.getSimpleSourceName();
    String proxyClassName = simpleClassName + "GetterAndSetter";
    String qualifiedProxyClassName = packageName + "." + proxyClassName;
    System.out.println("Created a class called: " + qualifiedProxyClassName);

    PrintWriter printWriter = context.tryCreate(logger, packageName, className);
    if (printWriter == null) return null;
      ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, className);
      composerFactory.addImport("test.project.shared.GetterAndSetter");
      composerFactory.addImplementedInterface("GetterAndSetter<" + underlyingTypeName + ">");
      SourceWriter writer = composerFactory.createSourceWriter(context, printWriter);
      if (writer != null) {
        JField[] fields = requestedClass.getFields();
        for (JField field : fields) {
          createSetterMethodForField(typeName, writer, field);
        }
        writer.indent();
        writer.println("public void set(" + typeName + " target, String path, Object value) {");
        writer.indent();
        createIfBlockForFields(writer, fields, true);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.println("public <K> K get(" + typeName + " target, String path) {");
        writer.indent();
        createIfBlockForFields(writer, fields, false);
        writer.outdent();
        writer.println("}");
        writer.println();
        writer.outdent();
        writer.commit(logger);
      }
      return packageName + "." + proxyClassName;
    } catch(NotFoundException nfe) {
      throw new UnableToCompleteException();
    }
  }
}
公共类TestGenerator扩展了生成器{
@凌驾
公共字符串生成(TreeLogger、GeneratorContext上下文、,
字符串类型名)引发UnableToCompleteException{
试一试{
TypeOracleOracle=context.getTypeOracle();
JClassType requestedClass=oracle.getType(typeName);
字符串packageName=requestedClass.getPackage().getName();
字符串simpleClassName=requestedClass.getSimpleSourceName();
字符串proxyClassName=simpleClassName+“GetterAndSetter”;
字符串qualifiedProxyClassName=packageName+“+”proxyClassName;
System.out.println(“创建了一个名为:“+qualifiedProxyClassName”的类);
PrintWriter PrintWriter=context.tryCreate(记录器、packageName、类名);
if(printWriter==null)返回null;
ClassSourceFileComposer工厂Composer工厂=新的ClassSourceFileComposer工厂(packageName,className);
addImport(“test.project.shared.GetterAndSetter”);
Composer Factory.addImplementedInterface(“GetterAndSetter”);
SourceWriter=composerFactory.createSourceWriter(上下文,printWriter);
if(writer!=null){
JField[]fields=requestedClass.getFields();
for(JField字段:字段){
createSetterMethodForField(打字机、打字机、字段);
}
writer.indent();
println(“公共无效集(“+typeName+”目标,字符串路径,对象值){”);
writer.indent();
createIfBlockForFields(writer,fields,true);
writer.outdent();
writer.println(“}”);
writer.println();
println(“public K get(“+typeName+”目标,字符串路径){”);
writer.indent();
createIfBlockForFields(writer,fields,false);
writer.outdent();
writer.println(“}”);
writer.println();
writer.outdent();
writer.commit(记录器);
}
返回packageName+“+”proxyClassName;
}捕获(未发现异常nfe){
抛出新的UnableToCompleteException();
}
}
}

我希望这对您有所帮助。

鉴于上述讨论,我决定补充我先前的答案。 首先,据我所知,您无法使用现有的i18n Maven目标(以及GWT的I18NCreator)来完成所要求的任务。 其次,在对我建议的发电机解决方案进行了更多研究后,我发现:

  • Michael是对的,您不会像上面建议的那样使用带有查找属性(GWT中的sin)的接口方法在编译时发现错误。然而,这仍然是最简单/最快捷的方法
  • 您可以通过编写自己的接口来确保编译时检查 与属性文件保持最新,每个属性有一个方法,然后获取 生成器来编写实现该接口的类。通知 更改属性文件上的属性时,只需 更改您编写的接口。如果你已经编写了生成器 正确地说,它将永远不会再被改变!最好的办法 关于方法名可能遵循GWT:如果调用了属性 .prop.one,则方法名称为_prop_one(..)
  • 如果您确实不想手动维护接口,那么 我可以看到的是,您可以编写自己的I18NCreator版本。 这是因为maven goal i18n不是GWT编译器 参数,但调用maven插件编写
    基于在中找到的属性文件的消息/常量接口 类路径。因此,如果您编写自己的I18NCreator,您将
    还必须编写一个Maven插件,您可以使用它来调用之前 编译GWT应用程序。或者,为了更简单,你可以 手动运行I18NCreator(使用良好的旧java命令来运行 每次更改属性文件密钥时(当然,
    当只更改实际消息时,不需要运行它)
就个人而言,我只需要编写和维护我的属性文件以及手动镜像它的接口。生成器将始终查看属性文件并生成相应的方法