I have an XML-based database and I have defined a User model with a list of references to Role (another model). I have attached an XMLAdapter to roles property to auto-populate roles. For that, I've @autowired the RoleRepository in this adapter.
However, the repository is never autowired (always null
), no matter what I do. I have configured Compile-Time Weaving, Load-Time Weaving, and also tried an instrumentation java agent that is able to load itself into the running JVM invesdwin-instrument
.
@Configurable(autowire = Autowire.BY_TYPE)
public class RoleAdapter extends XmlAdapter<String, List<Role>> {
@Autowired
protected RoleRepository roleRepository;
public RoleAdapter() {
}
@Override
public List<Role> unmarshal(String nameList) throws Exception {
// code using roleRepository
}
@Override
public String marshal(List<Role> roles) throws Exception {
// some code
}
}
@SpringBootApplication
@EnableConfigurationProperties({MyProperties.class})
@EntityScan(basePackages = { ... })
@EnableDiscoveryClient
@EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving
.AspectJWeaving.ENABLED)
@EnableSpringConfigured // tried this in a separate config
public class MyApplication {
static { // this was not here, added in a desperate move
DynamicInstrumentationLoader.waitForInitialized();
DynamicInstrumentationLoader.initLoadTimeWeavingContext();
}
// some code
/**
* Main method, used to run the application.
*
* @param args the command line arguments
*/
public static void main(String[] args) {
// dynamically attach java agent to jvm if not already present
DynamicInstrumentationLoader.waitForInitialized();
// weave all classes before they are loaded as beans
DynamicInstrumentationLoader.initLoadTimeWeavingContext();
if (!InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
throw new IllegalStateException("Instrumentation not available!");
} else { // it always gets here
System.out.println("Instrumentation available!");
}
SpringApplication app = new SpringApplication(MyApplication.class);
DefaultProfileUtil.addDefaultProfile(app);
Environment env = app.run(args).getEnvironment();
logApplicationStartup(env);
}
// more code
}
And the roles field in User
@XmlElement(type = String.class)
@XmlJavaTypeAdapter(RoleAdapter.class)
@XmlSchemaType(name = "IDREFS")
protected List<Role> roles;
I would like to know what I've missed here with weaving. A simpler way to achieve these auto-populating properties is also welcome.
"Solved" the problem by forgetting Compile-Time Weaving and Load-Time Weaving, and injecting RolesRepository
into UsersRepository
, initializing an instance of the RoleAdapter
with the injected repository and add this instance into the unmarshaller.
@Repository
public class UserRepository extends TimestampRepository<User> {
public static final String USERS_BY_USERNAME_CACHE = "usersByUsername";
public static final String USERS_BY_EMAIL_CACHE = "usersByEmail";
public UserRepository(
MyProperties myProperties,
ExistTemplate existTemplate,
Jaxb2Marshaller marshaller,
Jaxb2Marshaller unmarshaller,
RoleRepository roleRepository) {
super(
new UserEntityInformation(myProperties.getDatabase().getDbname()),
existTemplate, marshaller, unmarshaller);
marshaller.setAdapters(new RoleAdapter(roleRepository));
unmarshaller.setAdapters(new RoleAdapter(roleRepository));
}
// more code
}
public class RoleAdapter extends XmlAdapter<String, List<Role>> {
protected final RoleRepository roleRepository;
public RoleAdapter(RoleRepository roleRepository) {
this.roleRepository = roleRepository;
}
@Override
public List<Role> unmarshal(String nameList) throws Exception {
// code using roleRepository
}
@Override
public String marshal(List<Role> roles) throws Exception {
// some code
}
}