How to initialize the final variable by Spring #PostConstruct? - java

I have to initialize some final variable,but these value need to be read by Spring Properties
public class CrawlerClient{
#Autowired
#Qualifier("crawlerProperties")
private Properties crawlerProperties;
private Integer final maxTopic;
public static void main(String[] args) {
//initialize();
}
#PostConstruct
private void initialize(){
List<Topic> topics = topicBusiness.getAll();
List<Blogger> bloggers = bloggerBusiness.getAll();
List<Clue> clues = clueBusiness.getAll();
ClueQueue.addAll(clues);
TopicQueue.addAll(topics);
BloggerQueue.addAll(bloggers);
}
..
}
I want to initialize the variable of "maxTopic",but value is in Properties,So I can't do it in construction,how can I do for this?I just know remove the key of "final".
Finally,I do it by this way:
final Integer maxTopic;
final Integer maxBlogger;
final Integer maxClue;
#Autowired
public CrawlerClient(#Qualifier("crawlerProperties")Properties crawlerProperties){
this.maxTopic = Integer.parseInt(crawlerProperties.getProperty("MaxTopic"));
this.maxBlogger = Integer.parseInt(crawlerProperties.getProperty("MaxBlogger"));
this.maxClue = Integer.parseInt(crawlerProperties.getProperty("MaxClue"));
}
Can anyone solve it by the better way?

I believe you can achieve what you want with constructor injection:
#Component
public class CrawlerClient{
private Properties crawlerProperties;
private final Integer maxTopic;
#Autowired
public CrawlerClient(#Qualifier("crawlerProperties") Properties crawlerProperties,
#Value("maxTopic") Integer maxTopic){
this.crawlerProperties = crawlerProperties;
this.maxTopic = maxTopic;
List<Topic> topics = topicBusiness.getAll();
List<Blogger> bloggers = bloggerBusiness.getAll();
List<Clue> clues = clueBusiness.getAll();
ClueQueue.addAll(clues);
TopicQueue.addAll(topics);
BloggerQueue.addAll(bloggers);
}
..
}

Related

Would setting a field in a class as a new instance of the same class cause memory overflow? InetValidator class (apache.commons)

I am using InetValidator class from apache.commons in my project to validate IP addresses. While going through the source code,
public class InetAddressValidator implements Serializable {
private static final int IPV4_MAX_OCTET_VALUE = 255;
private static final int MAX_UNSIGNED_SHORT = 65535;
private static final int BASE_16 = 16;
private static final long serialVersionUID = -919201640201914789L;
private static final String IPV4_REGEX = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
private static final int IPV6_MAX_HEX_GROUPS = 8;
private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4;
private static final InetAddressValidator VALIDATOR = new InetAddressValidator();
private final RegexValidator ipv4Validator = new RegexValidator("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
public InetAddressValidator() {
}
public static InetAddressValidator getInstance() {
return VALIDATOR;
}
I observed there is a VALIDATOR field which is calling the constructor again.
What I'm confused with is if I create a new instance of this class as,
InetAddressValidator addressValidator = new InetAddressValidator();
won't it will recursively keep creating new instances of the same class (as the field VALIDATOR creates a new instance everytime) and eventually I'm gonna run out of heap space?
I haven't tested this yet, but wondering if this is something I have to keep in mind while testing.
private static final InetAddressValidator VALIDATOR = new InetAddressValidator();
it's a static field, so it will be instantiated just once at class load time, not per-instance in the constructor.
Recursive call
InetAddressValidator addressValidator = new InetAddressValidator(); Recursive call

How to map one object to the other object in java

I am implementing a component where one component receive a message, it sends another message to Audit component so it can be audited.
Audit handler has model called AuditObject, and my component has MessageObject. Here is the code:
public final class AuditObject {
private final Long id;
private final String studyUid;
private final AuditPatient patient;
...
}
public final class MessageObject {
private final Long id;
private final String studyUid;
private final PatientObject patient;
private final String accessorName;
...
}
AuditPatient and PatientObject have same variables.
I am trying to send it through amqp connection via jms message. I already have MessageGateway. So my code will look like this on my side.
public void send(MessageObject messageObject) {
//translate MessageObject to AuditObject
messageGateway.send(auditObject, endpoint);
}
What is the best way to translate(or map) MessageObject to AuditObject? Do I have to manually create each fields by assigning them? What is the best way to approach this problem?
Use static method in a class to convert one object to another and call it.
class ConvertObject {
public static AuditObject convertMessageObjectToAudioObject(MessageObject messageObject) {
AuditObject auditObject = new AuditObject();
auditObject.setStudyUid(messageObject.getStudyUid());
auditObject.setPatient(messageObject.getPatient());
return auditObject;
}
}
public void send(MessageObject messageObject) {
AuditObject auditObject = ConvertObject.convertMessageObjectToAudioObject(messageObject);
messageGateway.send(auditObject, endpoint);
}

Mockito mock with when returns null

I mock articleElementSelector.getTag() to return a string and use InjectMocks annotation to inject the mock into the constructor. In the debugger, I see that articleElementSelector is mocked (because of the CGLib stuff), but when getTag() is invoked, it returns null.
HomePageScraperTest:
public class HomePageScraperTest extends UnitTest {
private static final String ARTICLE_TAG = "article";
private static final String URL_HOME_ARTICLE_1 = "http://www.home1.com";
private static final String URL_HOME_ARTICLE_2 = "http://www.home2.com";
#InjectMocks
private HomePageScraper homePageScraper;
#Mock
private JsoupParser jsoupParser;
#Mock
private ArticleScraper articleScraper;
#Mock
private ArticleElementSelector articleElementSelector;
#Mock
private Document homeDocument;
#Mock
private Element element1;
#Mock
private Element element2;
#Mock
private Elements elements1;
#Mock
private Elements elements2;
private URL homeUrl;
private Elements homeArticleElements = new Elements();
private Article homeArticle1;
private Article homeArticle2;
#Before
public void setUp() throws Exception {
homeUrl = new URL(URL_HOME_ARTICLE_1);
homeArticleElements.addAll(asList(element1, element2));
homeArticle1 = anArticle().withTitle("article1").build();
homeArticle2 = anArticle().withTitle("article2").build();
}
#Test
public void scrape() {
HomePage homePage = new HomePage(homeUrl);
when(articleElementSelector.getTag()).thenReturn(ARTICLE_TAG);
when(jsoupParser.parse(homeUrl)).thenReturn(homeDocument);
when(homeDocument.select(ARTICLE_TAG)).thenReturn(homeArticleElements);
when(element1.select("a")).thenReturn(elements1);
when(elements1.attr("href")).thenReturn(URL_HOME_ARTICLE_1);
when(element2.select("a")).thenReturn(elements2);
when(elements2.attr("href")).thenReturn(URL_HOME_ARTICLE_2);
when(articleScraper.scrape(URL_HOME_ARTICLE_1)).thenReturn(homeArticle1);
when(articleScraper.scrape(URL_HOME_ARTICLE_2)).thenReturn(homeArticle2);
List<Article> articles = homePageScraper.scrape(homePage);
assertThat(articles).containsOnly(homeArticle1, homeArticle2);
}
}
HomePageScraper (only relevant code)
#Component
public class HomePageScraper extends AbstractPageScraper {
private static final int HEADLINER_COUNT = 5;
public HomePageScraper(JsoupParser parser, ArticleElementSelector articleElementSelector, ArticleScraper articleScraper) {
super(parser, articleElementSelector, articleScraper);
}
}
AbstractPageScraper
public abstract class AbstractPageScraper {
private final String ARTICLE_TAG;
private JsoupParser parser;
ArticleScraper articleScraper;
public AbstractPageScraper(JsoupParser parser, ArticleElementSelector articleElementSelector, ArticleScraper articleScraper) {
this.parser = parser;
ARTICLE_TAG = articleElementSelector.getTag(); // here the mock returns null
this.articleScraper = articleScraper;
}
}
The test worked before but after I refactored it, pulling up duplicate code in the abstract class, I bumped on this one.

Can't override node settings in ES integration test

I am writing an integration test for elasticsearch 5.3.
public class ProtectedWordsIndexTests extends ESIntegTestCase {
private final WordDelimiterActionListener wordsListener =
WordDelimiterActionListener.getInstance();
private final static String INDEX_NAME = "protected_words";
private final static String TYPE_NAME = "word";
private final static String FILTER_NAME = "my_word_delimiter";
#Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singleton(WordDelimiterPlugin.class);
}
#Override
protected Settings nodeSettings(int nodeOrdinal) {
return builder()
.put("plugin.types", TYPE_NAME)
.put("plugin.dynamic_word_delimiter.refresh_interval", "500ms")
.put(super.nodeSettings(nodeOrdinal))
.build();
}
public void testAddWordToIndex() throws Exception {
Settings indexSettings = builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put("index.analysis.filter.my_word_delimiter.type", "dynamic_word_delimiter")
.build();
TokenFilterFactory filterFactory = filterFactory(indexSettings, FILTER_NAME);
createIndex(INDEX_NAME);
ensureGreen();
client().prepareIndex(INDEX_NAME, TYPE_NAME, "1")
.setSource("word", "1tb")
.execute();
Thread.sleep(TimeValue.timeValueSeconds(1).getMillis());
Set<String> protectedWords = wordsListener.getProtectedWords();
assertTrue(protectedWords.size() == 1);
}
}
When I am running testAddWordToIndex() I am getting the following error:
"java.lang.IllegalArgumentException: unknown setting
[plugin.dynamic_word_delimiter.refresh_interval] please check that any
required plugins are installed, or check the breaking changes
documentation for removed settings"
If I remove the following part and increase the refresh interval to be more than the default, the test passes. So I just can't override this.
.put("plugin.dynamic_word_delimiter.refresh_interval", "500ms")
The default refresh interval is declared here:
public class WordDelimiterRunnable extends AbstractRunnable {
public static final TimeValue REFRESH_INTERVAL = TimeValue.timeValueSeconds(20);
public static final String INDEX_NAME = "protected_words";
public static final String INDEX_TYPE = "word";
public static final int RESULTS_SIZE = 10000;
private volatile boolean running;
private final Client client;
private final String index;
private final long interval;
private final String type;
public WordDelimiterRunnable(Client client, Settings settings) {
this.client = client;
this.index = settings.get("plugin.dynamic_word_delimiter.protected_words_index", INDEX_NAME);
this.type = settings.get("plugin.dynamic_word_delimiter.protected_words_type", INDEX_TYPE);
this.interval = settings.getAsTime("plugin.dynamic_word_delimiter.refresh_interval", REFRESH_INTERVAL).getMillis();
}
// more code here
}
You need to register the setting using the SettingsModule#registerSettings(Setting) method as explain here:
https://www.elastic.co/guide/en/elasticsearch/reference/5.x/breaking_50_settings_changes.html#breaking_50_settings_changes

Inline instanced class as parameter in an Enum

I'm new in java programming and trying to learn it.
I ran into a problem that cannot find a solution for it in the web:
I have an enum, that is a "list" of actions and each of them has a property
of type Actions that conains a list of possible subactions. The subacions are constant string.
I'd like to instanziate a anonymus instance of Actions in the enum constructor so that
in addition to the standart subactions, each enum could have its subactions
I tried to write an enum like the following
public enum Action {
ACTION1("One", new Actions(){
public static final String TEST = "test";
}),
ACTION2("TWO", null),
ACTION3("THREE,null);
private final String act;
public final Actions actions;
private Action(String act, Actions actions) {
this.act = act;
this.actions = actions;
}
}
and this is Actions class
public class Actions {
public static final String SUBACTION_TEST1 = "suoOne";
public static final String SUBACTION_TEST2 = "subTwo";
}
than, this is how I use the Action enum:
String as = Action.ACTION1.params.SUBACTION_TEST1;
and up to here it wors but I'cannot write this:
String ast = Action.ACTION1.params.TEST;
I know that probably this approach is wrong but before the change the implementation
I'd like to know why doesn't work.
Thanks.
Your enum has no property named params, which is the immediate reason your code example does not work. One thing you could do to improve this design, is to have your Actions class return the list of sub-actions via a well defined method:
public class Actions {
public static final String SUBACTION_TEST1 = "suoOne";
public static final String SUBACTION_TEST2 = "subTwo";
public List<String> getSubActions() {
return Arrays.asList(SUBACTION_TEST1, SUBACTION_TEST2);
}
}
public enum Action {
ACTION1("One", new Actions(){
public static final String TEST = "test";
#Override
public List<String> getSubActions() {
return Arrays.asList(TEST);
}
}),
private final String act;
private final Actions actions;
private Action(String act, Actions actions) {
this.act = act;
this.actions = actions;
}
public Actions getActions() {
return actions;
}
}
And to use this:
List<String> subActionList = Action.ACTION1.getSubActions();

Categories

Resources