Cómo detectar y solucionar un problema de inyección de dependencia de Guice utilizando Sensei
El propio proyecto Sensei tiene su propio conjunto de recetas que se han ido construyendo con el tiempo. Esta entrada del blog es un ejemplo de uno de los escenarios para los que el equipo de Sensei construyó una receta. Una configuración errónea de Guice, que llevó a que se reportara una NullPointerException en tiempo de ejecución durante las pruebas.
Esto se puede generalizar a muchos escenarios de Inyección de Dependencia donde el código es sintácticamente correcto, pero debido a que la configuración del cableado era incorrecta, se cuela un error.
Esto suele ocurrir cuando estamos aprendiendo la tecnología, y seguimos cometiendo el simple error de olvidarnos de cablear las cosas. Pero esto también le ocurre a los profesionales con experiencia porque, bueno... todos cometemos errores, y puede que no tengamos Unit Tests para cubrir todo.

Excepciones en tiempo de ejecución por cableado incorrecto de inyección de dependencia
El código siguiente falla en tiempo de ejecución con una NullPointerException.
injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());
El código es sintácticamente correcto, pero falla porque hemos omitido una requestStaticInjection en nuestra configuración de SystemOutModule.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
}
}
Cuando intentamos utilizar el reportero, creado con el Injector, no se instancian completamente y recibimos una NullPointerException cuando llamamos a reportThisMany.
Puede que se nos haya pasado en la revisión del código, o que no hayamos hecho pruebas unitarias que activen la inyección de dependencias, y se nos haya escapado en la compilación.
Señales de advertencia
En este caso, hay una señal de advertencia, el CountReporter tiene un campo estático anotado con @Inject pero... la propia clase CountReporter es paquete privado.
En una base de código complicada, esto podría ser una señal de advertencia de que el código es incorrecto porque la clase del módulo que configura los enlaces debe estar en el mismo paquete para que esto funcione.
class CountReporter {
@Inject
private static ILineReporter reporter;
Otro error que cometimos, y que podríamos haber detectado en una revisión de código, es que nos olvidamos de vincular realmente los campos en el método SystemOutModule configure.
binder().requestStaticInjection(CountReporter.class);
Si hubiéramos escrito el código de requestStaticInjection entonces el Error de Sintaxis generado al intentar usar el CountReporter nos habría alertado del simple error.
> 'reporters.CountReporter' no es público en 'reporters'. No se puede acceder desde fuera del paquete
Lamentablemente. Nos olvidamos y no había señales de advertencia sintáctica en el código.
¿Cómo puede ayudar Sensei ?
Probablemente no usaríamos Sensei para recoger el requestStaticInjection que falta, ya que todo nuestro cableado de configuración de Guice necesitaría usar ese método, y no podemos garantizar que todo el cableado vaya a ser tan simple como este caso de uso.
Podríamos escribir una regla en Sensei para buscar algunas señales de advertencia de que nuestro código no está a la altura.
En este caso eso significaría:
- Encontrar cualquier clase con campos anotados @Inject
- Donde las clases no son públicas.
Lo anterior fue la señal de advertencia de que era poco probable que estuvieran conectados.
Al crear una receta, entonces tendremos una señal de alerta temprana, durante la codificación, y reduciremos la dependencia de nuestros pull requests o de la resolución de nuestra deuda tecnológica para permitirnos añadir Unit Tests.
¿Cómo crear una receta?
La tarea que quiero completar es:
- Crear una receta que coincida con los campos anotados con @Inject que están en clases privadas protegidas
Eso debería darnos suficiente aviso para identificar cualquier módulo que lo utilice y añadir el código de cableado que falta.
En mi clase CountReporter, usaré Alt+Enter para crear una nueva receta y empezaré desde cero
Le pondré un nombre y añadiré una descripción:
Nombre: Guice: Campo inyectado no público
Descripción: Si el campo inyectado no es público el código podría no estar conectado
Nivel: Advertencia
La búsqueda que escribo busca una clase con un campo anotado como Inject, pero que no ha sido delimitado como público.
búsqueda:
campo:
con:
anotación:
tipo: "com.google.inject.Inject"
en:
clase:
sin:
modificador: "public"

Fijar
El QuickFix de la receta modificará la clase inyectada cambiando el ámbito. Pero ese no es el único código que tengo que cambiar.
availableFixes:
- nombre: "Cambiar la clase a pública. Recuerda solicitar también la inyección en esta clase"
actions:
- changeModifiers:
visibility: "public"
target: "parentClass"

Cuando la receta se dispara todavía tengo que realizar un paso manual en mi código, añadiendo la línea que contiene requestStaticInjection para instanciar completamente el objeto.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
// instantiate via dependency injection
binder().requestStaticInjection(CountReporter.class);
}
}
Potencialmente podría escribir otra receta para recoger esto. Probablemente no lo haría a menos que olvidar añadir la inyección estática se convirtiera en un error semi-regular que cometiera al codificar.
Resumen
Si alguna vez nos encontramos cometiendo un error con un patrón de raíz común, entonces Sensei puede ayudar a codificar el conocimiento en torno a la detección y corrección del problema, y entonces, con suerte, no se deslizará a través de las revisiones de código y en la producción.
A veces, las recetas que escribimos identifican patrones heurísticos, es decir, que su coincidencia no garantiza que haya un problema, pero es probable que lo haya.
Además, las recetas y los QuickFixes que escribimos no tienen que ser totalmente exhaustivos, sino que tienen que ser lo suficientemente buenos como para ayudarnos a identificar y solucionar los problemas sin ser demasiado complicados. Porque cuando se complican en exceso se vuelven más difíciles de entender y de mantener.
---
Puede instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busque "sensei secure code".
El código fuente y las recetas de este post se encuentran en el repositorio `sensei-blog-examples` de la cuenta de GitHub de Secure Code Warrior , en el módulo `guiceexamples`.
https://github.com/securecodewarrior/sensei-blog-examples


Un escenario de ejemplo para una configuración errónea de Guice, que puede llevar a que se informe de una NullPointerException en tiempo de ejecución durante las pruebas.
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Reservar una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.


El propio proyecto Sensei tiene su propio conjunto de recetas que se han ido construyendo con el tiempo. Esta entrada del blog es un ejemplo de uno de los escenarios para los que el equipo de Sensei construyó una receta. Una configuración errónea de Guice, que llevó a que se reportara una NullPointerException en tiempo de ejecución durante las pruebas.
Esto se puede generalizar a muchos escenarios de Inyección de Dependencia donde el código es sintácticamente correcto, pero debido a que la configuración del cableado era incorrecta, se cuela un error.
Esto suele ocurrir cuando estamos aprendiendo la tecnología, y seguimos cometiendo el simple error de olvidarnos de cablear las cosas. Pero esto también le ocurre a los profesionales con experiencia porque, bueno... todos cometemos errores, y puede que no tengamos Unit Tests para cubrir todo.

Excepciones en tiempo de ejecución por cableado incorrecto de inyección de dependencia
El código siguiente falla en tiempo de ejecución con una NullPointerException.
injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());
El código es sintácticamente correcto, pero falla porque hemos omitido una requestStaticInjection en nuestra configuración de SystemOutModule.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
}
}
Cuando intentamos utilizar el reportero, creado con el Injector, no se instancian completamente y recibimos una NullPointerException cuando llamamos a reportThisMany.
Puede que se nos haya pasado en la revisión del código, o que no hayamos hecho pruebas unitarias que activen la inyección de dependencias, y se nos haya escapado en la compilación.
Señales de advertencia
En este caso, hay una señal de advertencia, el CountReporter tiene un campo estático anotado con @Inject pero... la propia clase CountReporter es paquete privado.
En una base de código complicada, esto podría ser una señal de advertencia de que el código es incorrecto porque la clase del módulo que configura los enlaces debe estar en el mismo paquete para que esto funcione.
class CountReporter {
@Inject
private static ILineReporter reporter;
Otro error que cometimos, y que podríamos haber detectado en una revisión de código, es que nos olvidamos de vincular realmente los campos en el método SystemOutModule configure.
binder().requestStaticInjection(CountReporter.class);
Si hubiéramos escrito el código de requestStaticInjection entonces el Error de Sintaxis generado al intentar usar el CountReporter nos habría alertado del simple error.
> 'reporters.CountReporter' no es público en 'reporters'. No se puede acceder desde fuera del paquete
Lamentablemente. Nos olvidamos y no había señales de advertencia sintáctica en el código.
¿Cómo puede ayudar Sensei ?
Probablemente no usaríamos Sensei para recoger el requestStaticInjection que falta, ya que todo nuestro cableado de configuración de Guice necesitaría usar ese método, y no podemos garantizar que todo el cableado vaya a ser tan simple como este caso de uso.
Podríamos escribir una regla en Sensei para buscar algunas señales de advertencia de que nuestro código no está a la altura.
En este caso eso significaría:
- Encontrar cualquier clase con campos anotados @Inject
- Donde las clases no son públicas.
Lo anterior fue la señal de advertencia de que era poco probable que estuvieran conectados.
Al crear una receta, entonces tendremos una señal de alerta temprana, durante la codificación, y reduciremos la dependencia de nuestros pull requests o de la resolución de nuestra deuda tecnológica para permitirnos añadir Unit Tests.
¿Cómo crear una receta?
La tarea que quiero completar es:
- Crear una receta que coincida con los campos anotados con @Inject que están en clases privadas protegidas
Eso debería darnos suficiente aviso para identificar cualquier módulo que lo utilice y añadir el código de cableado que falta.
En mi clase CountReporter, usaré Alt+Enter para crear una nueva receta y empezaré desde cero
Le pondré un nombre y añadiré una descripción:
Nombre: Guice: Campo inyectado no público
Descripción: Si el campo inyectado no es público el código podría no estar conectado
Nivel: Advertencia
La búsqueda que escribo busca una clase con un campo anotado como Inject, pero que no ha sido delimitado como público.
búsqueda:
campo:
con:
anotación:
tipo: "com.google.inject.Inject"
en:
clase:
sin:
modificador: "public"

Fijar
El QuickFix de la receta modificará la clase inyectada cambiando el ámbito. Pero ese no es el único código que tengo que cambiar.
availableFixes:
- nombre: "Cambiar la clase a pública. Recuerda solicitar también la inyección en esta clase"
actions:
- changeModifiers:
visibility: "public"
target: "parentClass"

Cuando la receta se dispara todavía tengo que realizar un paso manual en mi código, añadiendo la línea que contiene requestStaticInjection para instanciar completamente el objeto.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
// instantiate via dependency injection
binder().requestStaticInjection(CountReporter.class);
}
}
Potencialmente podría escribir otra receta para recoger esto. Probablemente no lo haría a menos que olvidar añadir la inyección estática se convirtiera en un error semi-regular que cometiera al codificar.
Resumen
Si alguna vez nos encontramos cometiendo un error con un patrón de raíz común, entonces Sensei puede ayudar a codificar el conocimiento en torno a la detección y corrección del problema, y entonces, con suerte, no se deslizará a través de las revisiones de código y en la producción.
A veces, las recetas que escribimos identifican patrones heurísticos, es decir, que su coincidencia no garantiza que haya un problema, pero es probable que lo haya.
Además, las recetas y los QuickFixes que escribimos no tienen que ser totalmente exhaustivos, sino que tienen que ser lo suficientemente buenos como para ayudarnos a identificar y solucionar los problemas sin ser demasiado complicados. Porque cuando se complican en exceso se vuelven más difíciles de entender y de mantener.
---
Puede instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busque "sensei secure code".
El código fuente y las recetas de este post se encuentran en el repositorio `sensei-blog-examples` de la cuenta de GitHub de Secure Code Warrior , en el módulo `guiceexamples`.
https://github.com/securecodewarrior/sensei-blog-examples

El propio proyecto Sensei tiene su propio conjunto de recetas que se han ido construyendo con el tiempo. Esta entrada del blog es un ejemplo de uno de los escenarios para los que el equipo de Sensei construyó una receta. Una configuración errónea de Guice, que llevó a que se reportara una NullPointerException en tiempo de ejecución durante las pruebas.
Esto se puede generalizar a muchos escenarios de Inyección de Dependencia donde el código es sintácticamente correcto, pero debido a que la configuración del cableado era incorrecta, se cuela un error.
Esto suele ocurrir cuando estamos aprendiendo la tecnología, y seguimos cometiendo el simple error de olvidarnos de cablear las cosas. Pero esto también le ocurre a los profesionales con experiencia porque, bueno... todos cometemos errores, y puede que no tengamos Unit Tests para cubrir todo.

Excepciones en tiempo de ejecución por cableado incorrecto de inyección de dependencia
El código siguiente falla en tiempo de ejecución con una NullPointerException.
injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());
El código es sintácticamente correcto, pero falla porque hemos omitido una requestStaticInjection en nuestra configuración de SystemOutModule.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
}
}
Cuando intentamos utilizar el reportero, creado con el Injector, no se instancian completamente y recibimos una NullPointerException cuando llamamos a reportThisMany.
Puede que se nos haya pasado en la revisión del código, o que no hayamos hecho pruebas unitarias que activen la inyección de dependencias, y se nos haya escapado en la compilación.
Señales de advertencia
En este caso, hay una señal de advertencia, el CountReporter tiene un campo estático anotado con @Inject pero... la propia clase CountReporter es paquete privado.
En una base de código complicada, esto podría ser una señal de advertencia de que el código es incorrecto porque la clase del módulo que configura los enlaces debe estar en el mismo paquete para que esto funcione.
class CountReporter {
@Inject
private static ILineReporter reporter;
Otro error que cometimos, y que podríamos haber detectado en una revisión de código, es que nos olvidamos de vincular realmente los campos en el método SystemOutModule configure.
binder().requestStaticInjection(CountReporter.class);
Si hubiéramos escrito el código de requestStaticInjection entonces el Error de Sintaxis generado al intentar usar el CountReporter nos habría alertado del simple error.
> 'reporters.CountReporter' no es público en 'reporters'. No se puede acceder desde fuera del paquete
Lamentablemente. Nos olvidamos y no había señales de advertencia sintáctica en el código.
¿Cómo puede ayudar Sensei ?
Probablemente no usaríamos Sensei para recoger el requestStaticInjection que falta, ya que todo nuestro cableado de configuración de Guice necesitaría usar ese método, y no podemos garantizar que todo el cableado vaya a ser tan simple como este caso de uso.
Podríamos escribir una regla en Sensei para buscar algunas señales de advertencia de que nuestro código no está a la altura.
En este caso eso significaría:
- Encontrar cualquier clase con campos anotados @Inject
- Donde las clases no son públicas.
Lo anterior fue la señal de advertencia de que era poco probable que estuvieran conectados.
Al crear una receta, entonces tendremos una señal de alerta temprana, durante la codificación, y reduciremos la dependencia de nuestros pull requests o de la resolución de nuestra deuda tecnológica para permitirnos añadir Unit Tests.
¿Cómo crear una receta?
La tarea que quiero completar es:
- Crear una receta que coincida con los campos anotados con @Inject que están en clases privadas protegidas
Eso debería darnos suficiente aviso para identificar cualquier módulo que lo utilice y añadir el código de cableado que falta.
En mi clase CountReporter, usaré Alt+Enter para crear una nueva receta y empezaré desde cero
Le pondré un nombre y añadiré una descripción:
Nombre: Guice: Campo inyectado no público
Descripción: Si el campo inyectado no es público el código podría no estar conectado
Nivel: Advertencia
La búsqueda que escribo busca una clase con un campo anotado como Inject, pero que no ha sido delimitado como público.
búsqueda:
campo:
con:
anotación:
tipo: "com.google.inject.Inject"
en:
clase:
sin:
modificador: "public"

Fijar
El QuickFix de la receta modificará la clase inyectada cambiando el ámbito. Pero ese no es el único código que tengo que cambiar.
availableFixes:
- nombre: "Cambiar la clase a pública. Recuerda solicitar también la inyección en esta clase"
actions:
- changeModifiers:
visibility: "public"
target: "parentClass"

Cuando la receta se dispara todavía tengo que realizar un paso manual en mi código, añadiendo la línea que contiene requestStaticInjection para instanciar completamente el objeto.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
// instantiate via dependency injection
binder().requestStaticInjection(CountReporter.class);
}
}
Potencialmente podría escribir otra receta para recoger esto. Probablemente no lo haría a menos que olvidar añadir la inyección estática se convirtiera en un error semi-regular que cometiera al codificar.
Resumen
Si alguna vez nos encontramos cometiendo un error con un patrón de raíz común, entonces Sensei puede ayudar a codificar el conocimiento en torno a la detección y corrección del problema, y entonces, con suerte, no se deslizará a través de las revisiones de código y en la producción.
A veces, las recetas que escribimos identifican patrones heurísticos, es decir, que su coincidencia no garantiza que haya un problema, pero es probable que lo haya.
Además, las recetas y los QuickFixes que escribimos no tienen que ser totalmente exhaustivos, sino que tienen que ser lo suficientemente buenos como para ayudarnos a identificar y solucionar los problemas sin ser demasiado complicados. Porque cuando se complican en exceso se vuelven más difíciles de entender y de mantener.
---
Puede instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busque "sensei secure code".
El código fuente y las recetas de este post se encuentran en el repositorio `sensei-blog-examples` de la cuenta de GitHub de Secure Code Warrior , en el módulo `guiceexamples`.
https://github.com/securecodewarrior/sensei-blog-examples

Haga clic en el siguiente enlace y descargue el PDF de este recurso.
Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Ver el informeReservar una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.
El propio proyecto Sensei tiene su propio conjunto de recetas que se han ido construyendo con el tiempo. Esta entrada del blog es un ejemplo de uno de los escenarios para los que el equipo de Sensei construyó una receta. Una configuración errónea de Guice, que llevó a que se reportara una NullPointerException en tiempo de ejecución durante las pruebas.
Esto se puede generalizar a muchos escenarios de Inyección de Dependencia donde el código es sintácticamente correcto, pero debido a que la configuración del cableado era incorrecta, se cuela un error.
Esto suele ocurrir cuando estamos aprendiendo la tecnología, y seguimos cometiendo el simple error de olvidarnos de cablear las cosas. Pero esto también le ocurre a los profesionales con experiencia porque, bueno... todos cometemos errores, y puede que no tengamos Unit Tests para cubrir todo.

Excepciones en tiempo de ejecución por cableado incorrecto de inyección de dependencia
El código siguiente falla en tiempo de ejecución con una NullPointerException.
injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());
El código es sintácticamente correcto, pero falla porque hemos omitido una requestStaticInjection en nuestra configuración de SystemOutModule.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
}
}
Cuando intentamos utilizar el reportero, creado con el Injector, no se instancian completamente y recibimos una NullPointerException cuando llamamos a reportThisMany.
Puede que se nos haya pasado en la revisión del código, o que no hayamos hecho pruebas unitarias que activen la inyección de dependencias, y se nos haya escapado en la compilación.
Señales de advertencia
En este caso, hay una señal de advertencia, el CountReporter tiene un campo estático anotado con @Inject pero... la propia clase CountReporter es paquete privado.
En una base de código complicada, esto podría ser una señal de advertencia de que el código es incorrecto porque la clase del módulo que configura los enlaces debe estar en el mismo paquete para que esto funcione.
class CountReporter {
@Inject
private static ILineReporter reporter;
Otro error que cometimos, y que podríamos haber detectado en una revisión de código, es que nos olvidamos de vincular realmente los campos en el método SystemOutModule configure.
binder().requestStaticInjection(CountReporter.class);
Si hubiéramos escrito el código de requestStaticInjection entonces el Error de Sintaxis generado al intentar usar el CountReporter nos habría alertado del simple error.
> 'reporters.CountReporter' no es público en 'reporters'. No se puede acceder desde fuera del paquete
Lamentablemente. Nos olvidamos y no había señales de advertencia sintáctica en el código.
¿Cómo puede ayudar Sensei ?
Probablemente no usaríamos Sensei para recoger el requestStaticInjection que falta, ya que todo nuestro cableado de configuración de Guice necesitaría usar ese método, y no podemos garantizar que todo el cableado vaya a ser tan simple como este caso de uso.
Podríamos escribir una regla en Sensei para buscar algunas señales de advertencia de que nuestro código no está a la altura.
En este caso eso significaría:
- Encontrar cualquier clase con campos anotados @Inject
- Donde las clases no son públicas.
Lo anterior fue la señal de advertencia de que era poco probable que estuvieran conectados.
Al crear una receta, entonces tendremos una señal de alerta temprana, durante la codificación, y reduciremos la dependencia de nuestros pull requests o de la resolución de nuestra deuda tecnológica para permitirnos añadir Unit Tests.
¿Cómo crear una receta?
La tarea que quiero completar es:
- Crear una receta que coincida con los campos anotados con @Inject que están en clases privadas protegidas
Eso debería darnos suficiente aviso para identificar cualquier módulo que lo utilice y añadir el código de cableado que falta.
En mi clase CountReporter, usaré Alt+Enter para crear una nueva receta y empezaré desde cero
Le pondré un nombre y añadiré una descripción:
Nombre: Guice: Campo inyectado no público
Descripción: Si el campo inyectado no es público el código podría no estar conectado
Nivel: Advertencia
La búsqueda que escribo busca una clase con un campo anotado como Inject, pero que no ha sido delimitado como público.
búsqueda:
campo:
con:
anotación:
tipo: "com.google.inject.Inject"
en:
clase:
sin:
modificador: "public"

Fijar
El QuickFix de la receta modificará la clase inyectada cambiando el ámbito. Pero ese no es el único código que tengo que cambiar.
availableFixes:
- nombre: "Cambiar la clase a pública. Recuerda solicitar también la inyección en esta clase"
actions:
- changeModifiers:
visibility: "public"
target: "parentClass"

Cuando la receta se dispara todavía tengo que realizar un paso manual en mi código, añadiendo la línea que contiene requestStaticInjection para instanciar completamente el objeto.
public class SystemOutModule extends AbstractModule {
@Override
protected void configure() {
binder().bind(ILineReporter.class).to(SystemOutReporter.class);
// instantiate via dependency injection
binder().requestStaticInjection(CountReporter.class);
}
}
Potencialmente podría escribir otra receta para recoger esto. Probablemente no lo haría a menos que olvidar añadir la inyección estática se convirtiera en un error semi-regular que cometiera al codificar.
Resumen
Si alguna vez nos encontramos cometiendo un error con un patrón de raíz común, entonces Sensei puede ayudar a codificar el conocimiento en torno a la detección y corrección del problema, y entonces, con suerte, no se deslizará a través de las revisiones de código y en la producción.
A veces, las recetas que escribimos identifican patrones heurísticos, es decir, que su coincidencia no garantiza que haya un problema, pero es probable que lo haya.
Además, las recetas y los QuickFixes que escribimos no tienen que ser totalmente exhaustivos, sino que tienen que ser lo suficientemente buenos como para ayudarnos a identificar y solucionar los problemas sin ser demasiado complicados. Porque cuando se complican en exceso se vuelven más difíciles de entender y de mantener.
---
Puede instalar Sensei desde IntelliJ usando "Preferences \ Plugins" (Mac) o "Settings \ Plugins" (Windows) y luego sólo busque "sensei secure code".
El código fuente y las recetas de este post se encuentran en el repositorio `sensei-blog-examples` de la cuenta de GitHub de Secure Code Warrior , en el módulo `guiceexamples`.
https://github.com/securecodewarrior/sensei-blog-examples
Índice
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior está a disposición de su organización para ayudarle a proteger el código a lo largo de todo el ciclo de vida de desarrollo de software y crear una cultura en la que la ciberseguridad sea una prioridad. Tanto si es director de AppSec, desarrollador, CISO o cualquier persona implicada en la seguridad, podemos ayudar a su organización a reducir los riesgos asociados a un código inseguro.
Reservar una demostraciónDescargarRecursos para empezar
Panorama de la gestión de riesgos de los promotores
La gestión de riesgos del desarrollador es un enfoque holístico y proactivo de la seguridad de las aplicaciones, centrado en quienes contribuyen al código y no en los bits y bytes de la propia capa de la aplicación.
Seguridad desde el diseño: Definición de las mejores prácticas, capacitación de los desarrolladores y evaluación comparativa de los resultados de la seguridad preventiva
En este documento de investigación, los cofundadores Secure Code Warrior , Pieter Danhieux y el Dr. Matias Madou, Ph.D., junto con los expertos colaboradores, Chris Inglis, ex Director Nacional Cibernético de EE.UU. (ahora Asesor Estratégico de Paladin Capital Group), y Devin Lynch, Director Senior, Paladin Global Institute, revelarán los hallazgos clave de más de veinte entrevistas en profundidad con líderes de seguridad empresarial, incluyendo CISOs, un VP de Seguridad de Aplicaciones y profesionales de seguridad de software.
Evaluación comparativa de las competencias en materia de seguridad: optimización del diseño seguro en la empresa
Encontrar datos significativos sobre el éxito de las iniciativas Secure-by-Design es notoriamente difícil. Los responsables de la seguridad de la información se enfrentan a menudo al reto de demostrar el rendimiento de la inversión (ROI) y el valor empresarial de las actividades de los programas de seguridad, tanto a nivel de las personas como de la empresa. Por no mencionar que a las empresas les resulta especialmente difícil obtener información sobre cómo se comparan sus organizaciones con los estándares actuales del sector. La Estrategia Nacional de Ciberseguridad del Presidente desafió a las partes interesadas a "adoptar la seguridad y la resiliencia desde el diseño". La clave para que las iniciativas de seguridad por diseño funcionen no es sólo dotar a los desarrolladores de las habilidades necesarias para garantizar un código seguro, sino también garantizar a los reguladores que esas habilidades están en su lugar. En esta presentación, compartimos una miríada de datos cualitativos y cuantitativos, derivados de múltiples fuentes primarias, incluidos puntos de datos internos recogidos de más de 250.000 desarrolladores, opiniones de clientes basadas en datos y estudios públicos. Aprovechando esta agregación de puntos de datos, pretendemos comunicar una visión del estado actual de las iniciativas Secure-by-Design en múltiples verticales. El informe detalla por qué este espacio está actualmente infrautilizado, el impacto significativo que un programa de mejora de las competencias puede tener en la mitigación de los riesgos de ciberseguridad y el potencial para eliminar categorías de vulnerabilidades de un código base.
Servicios profesionales - Acelerar con experiencia
El equipo de servicios de estrategia de programas (PSS) de Secure Code Warriorle ayuda a crear, mejorar y optimizar su programa de codificación segura. Tanto si empieza de cero como si está perfeccionando su enfoque, nuestros expertos le proporcionarán orientación personalizada.
Recursos para empezar
Revelado: Cómo define el sector cibernético la seguridad por diseño
En nuestro último libro blanco, nuestros cofundadores, Pieter Danhieux y el doctor Matias Madou, se sentaron con más de veinte líderes de seguridad empresarial, incluidos CISO, líderes de AppSec y profesionales de la seguridad, para averiguar las piezas clave de este rompecabezas y descubrir la realidad detrás del movimiento Secure by Design. Se trata de una ambición compartida por todos los equipos de seguridad, pero no de un libro de jugadas compartido.
¿Vibe Coding va a convertir tu código en una fiesta de fraternidad?
Vibe Coding es como una fiesta de fraternidad universitaria, y la IA es la pieza central de todos los festejos, el barril. Es muy divertido dar rienda suelta a la creatividad y ver adónde te lleva tu imaginación, pero después de unas cuantas borracheras, beber (o usar IA) con moderación es, sin duda, la solución más segura a largo plazo.