I have the following Spring Bean structure:
public abstract class XmlBaseChild {
protected Integer value;
protected String text;
#Autowired
transient protected MasterCodeService masterCodeService;
public XmlBaseChild(Integer value) {
setValue(value);
}
/**
* Set the Numeric value of the ChildView.
* This code is common for all childViews and handles a null value.
* #param value Numeric value of the ChildView
*/
#JsonProperty(value="id")
public void setValue(Integer value) {
if (value == null) {
this.value = null;
this.text = null;
return;
}
setConcreteValue(value);
}
/**
* Set the Numeric value of the ChildView.
* This code must be overridden by the concrete childViews.
* #param value Numeric value of the ChildView
*/
protected void setConcreteValue(Integer value){
boolean keyNotFound = true;
if (value != null && value > -1) {
this.value = value;
String messageKey = getValueFromMap(value, GetMasterCodeMapForChildView());
if (messageKey != null) {
this.text = LocalizeString(messageKey, null, getLocale);
keyNotFound = false;
}
}
if (keyNotFound){
throw new NotFoundException();
}
}
protected abstract Map<String, MasterCodeView> GetMasterCodeMapForChildView();
}
And the subclass:
#Component
#XmlRootElement(name=XmlDeployTool.VIEW_NAME)
public class XmlDeployTool extends XmlBaseChild {
public static Map<String, MasterCodeView> toolTypeCodes = new HashMap<String, MasterCodeView>();
/**
* Constructor for creating this object and preparing for marchalling (from java objects to xml/json).
* #param value Numeric value of the ChildView
* #param request HttpServletRequest
* #param includeSelf Include SELF link
* #param includeUP Include UP link
*/
public XmlDeployTool(Integer value) {
super(value);
}
/**
* Initialize the Tool Type codes after the component is wired (postconstruct),
* so that they are available in the constructor when an XmlDeploy object is created.
*/
#PostConstruct
protected void initializeDeployToolTypeCodes() {
toolTypeCodes = convertListToMap(masterCodeService.getToolTypeCodes());
}
#Override
protected Map<String, MasterCodeView> GetMasterCodeMapForChildView() {
return toolTypeCodes;
}
}
However, from what I understand from other posts like Order of #PostConstruct and inheritance, the #PostConstruct here normally executes AFTER the constructor is called. Then why is the toolTypeCodes map populated during the constructor? Is this part of the #Component annotation of Spring?
I also tried doing this with the masterCodeView map defined in the XmlBaseChild and only the PostConstruct method defined in the XmlDeployTool class, but that didn't work, the list didn't get initialized in that case. Why is this?
After checking the documentation and reading up some more, I figured out what's going on here:
Because my subclass is annotated with #Component, the PostConstruct triggers as part of the Spring startup process, even before any invocations of the normal constructor. Because of this, the static Map with MasterCodeViews gets populated, and since this is static, it stays populated as part of the subclass static properties. Because of this, this map has the proper usable data during construction.
When I tried to move the Map to the base class, In effect I turned this from a static property of the subclass to a static property of the subclass, which meant each constructor in turn populated it with the separate properties, leading to the map having the wrong data most of the time. When after that I tried to do this with a non-static map, the data wasn't retained when I invoked the constructor from code because this was effectively a new object with no initialized components.
Related
I am doing deserialization at the Listener in Spring Kafka. But this assumes that the type information was included or sent by a Spring Kafka producer. In my case the Json is being sent across by the Debezium MySQLConnector and it does not add this meta data. So I would like to add it to the requests. I understand its placed in the request somewhere in the JsonSerializer, and I looked at the source code but could not figure out exactly how to use this to add meta data type during serialization generically to a request. In particular what field holds this type information? And is it the class name of the java object that was serialized? I dont think just setting a default serializer is going to work because I have multiple consumers listening on different topics as one would expect. Except for the simplest cases this is just not going to work to set one default as i have many consumers and types that I am deserializing to. So this answer is not going to work in my case Kafka - Deserializing the object in Consumer
Update tried using Method Types on deserializer but have another issue: Kafka Spring Deserialzer returnType static method never called
See
public abstract class AbstractJavaTypeMapper implements BeanClassLoaderAware {
/**
* Default header name for type information.
*/
public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__";
/**
* Default header name for container object contents type information.
*/
public static final String DEFAULT_CONTENT_CLASSID_FIELD_NAME = "__ContentTypeId__";
/**
* Default header name for map key type information.
*/
public static final String DEFAULT_KEY_CLASSID_FIELD_NAME = "__KeyTypeId__";
/**
* Default header name for key type information.
*/
public static final String KEY_DEFAULT_CLASSID_FIELD_NAME = "__Key_TypeId__";
/**
* Default header name for key container object contents type information.
*/
public static final String KEY_DEFAULT_CONTENT_CLASSID_FIELD_NAME = "__Key_ContentTypeId__";
/**
* Default header name for key map key type information.
*/
public static final String KEY_DEFAULT_KEY_CLASSID_FIELD_NAME = "__Key_KeyTypeId__";
2 sets of headers (keys and values).
TypeId is for simple classes
If TypeId is a container List<?>
ContentTypeId is the contained type.
If TypeId is a Map
Key_TypeId is the key type.
This allows you to reconstruct a Map<Foo, Bar>.
These headers can either contain fully qualified class names, or tokens that map to class names via the classIdMappings map.
However, since version 2.5, it would be easier to use the new
Using Methods to Determine Types.
That way, you can set your own headers and examine them in the method.
EDIT
Here is a simple example:
#SpringBootApplication
public class Gitter76Application {
public static void main(String[] args) {
SpringApplication.run(Gitter76Application.class, args);
}
#Bean
public NewTopic topic() {
return TopicBuilder.name("gitter76").partitions(1).replicas(1).build();
}
#KafkaListener(id = "gitter76", topics = "gitter76")
public void listen(Foo in) {
System.out.println(in);
}
}
public class Foo {
private String bar;
public Foo() {
}
public Foo(String bar) {
this.bar = bar;
}
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return "Foo [bar=" + this.bar + "]";
}
}
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.trusted.packages=com.example.demo
$ kafkacat -P -b localhost:9092 -t gitter76 -H __TypeId__=com.example.demo.Foo
{"bar":"baz"}
^C
2020-08-08 09:32:10.034 INFO 58146 --- [ gitter76-0-C-1] o.s.k.l.KafkaMessageListenerContainer : gitter76: partitions assigned: [gitter76-0]
Foo [bar=baz]
I have a class Abc with method (body is not important):
/**
* #return SomeBaseClass
*/
function getAll() { ... }
In child class of Abc called AbcChild I'd like to redefine only type of returning class to see it properly in Netbeans. Can I do it without redefining method:
/**
* #return SomeClass
*/
function getAll() { return parent::getAll(); }
Try something like this:
/**
* #method SomeClass getAll()
*/
class AbcChild
{
// ....
}
More info about #method
No, because you need the child method code itself in order to have a child docblock to associate with it. If you have the docblock but not the method code, the docblock won't be tied to anything, and thus will have no effect. Most people dislike altering their code to accommodate docblock behavior, though it's never really bothered me to do so.
However, another option for you is to adjust the #return tag on the parent method, so that it lists all possible return types that you want to indicate the children could return. That makes me wonder, though... if you are not actually overriding the method itself, then how is the child class actually returning a different class than the parent? I can see ways to do this in my mind, involving class properties that contain the differing class objects, but they'd feel like code smells to me ;-)
If there is no method override code itself in the child, then I would choose to put all possible return types in the parent's #return.
Actually I think there is other way than full method override. You can change #return phpdoc block in the child interface which extends base interface. Let me explain with code what I mean:
interface EntityRepository
{
/**
* #return object
*/
public function get($id);
public function add($entity, $sync = false);
public function remove($entity, $sync = false);
// other methods common for custom repositories
}
interface ProjectRepository extends EntityRepository
{
/**
* #return Project
*/
public function get($id);
}
This is part of your domain. And now the concrete implementation taken from Symfony & Doctrine:
use Doctrine\ORM\EntityRepository;
use Model\Repository\EntityRepository as BaseEntityRepository;
abstract class DoctrineEntityRepository extends EntityRepository implements BaseEntityRepository
{
public function get($id)
{
$entity = $this->find($id);
if (!$entity) {
throw new EntityNotFoundException();
}
return $entity;
}
public function add($entity, $sync = false)
{
// method implementation
}
public function remove($entity, $sync = false)
{
// method implementation
}
}
use Model\Repository\ProjectRepository as BaseProjectRepository;
class ProjectRepository extends DoctrineEntityRepository implements BaseProjectRepository
{
public function specificQueryForProjects()
{
// method implementation
}
}
This way you dont have to override methods in child classes only because of code autocomplete. You just have to extend interfaces to let users of your API know that the return value changed.
I have to consume a REST api which follows a common syntax across all retrievable objects:
baseUrl + domainObjectName + qualifier
E.g.
"http://myweb.com/api/" + "cities" + "/{id}"
I created a BaseDao for my data layer and I would like to set up in DAO instantiation the base url for each domain object (baseUrl + domainObjectName). The problem is I have my api Base url defined in the properties file (and would like to keep it that way), and it is not available in the DAO constructor.
This is what I have:
public abstract class BaseDao {
protected static final String ID_QUALIFIER = "/{id}";
protected String domainObjectName = "";
protected String doBaseUrl = "";
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
}
When my dao is instantiated, apiBaseUrl is still null, although after creation it is indeed injecting the baseUrl property.
Is there any way around this, like injecting the property as a static constant?
This happens because Java doesn't allow to set fields of a class before the constructor is called. So Spring can't inject the value. There are two solutions:
Pass the value to the constructor instead (example 1)
Use #PostConstruct (example 2)
Example 1:
public GenericDaoRestImpl(
#Value("#{config['baseUrlRest']}") String apiBaseUrl
String domainObjectName
) {
...
}
Example 2:
#Value("#{config['baseUrlRest']}")
public String apiBaseUrl;
public GenericDaoRestImpl(String domainObjectName) {
this.domainObjectName = domainObjectName;
}
#PostConstruct
public void init() {
this.domainObjectName = domainObjectName;
this.doBaseUrl = apiBaseUrl + domainObjectName;
}
I prefer the #PostConstruct because constructor injection eventually leads to constructors with many parameters which makes them unwieldy.
If you don't like it, your third option is using the builder pattern with a fluent interface.
I have a model TestModel.java which contains a field declared like below
#Required
#IntegerAnnotation
#Column (length = 4, nullable = false)
public Integer sort;
For the default validation annotation of Play doesn't support Integer check, so I create an annotation validation for checking the input value is an Integer or not.
The IntegerAnnotation.java :
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Constraint(checkWith = IntegerCheck.class)
public #interface IntegerAnnotation {
String message() default IntegerCheck.message;}
}
and this annotation refers to an implementations of IntegerCheck.java
public class IntegerCheck extends AbstractAnnotationCheck<IntegerAnnotation>{
final static String message = "validation.integer";
#Override
public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) throws OValException {
// TODO Auto-generated method stub
if(value == null) return false;
return isInteger(value.toString());
}
private static boolean isInteger(String s) {
return isInteger(s,10);
}
private static boolean isInteger(String s, int radix) {
if(s.isEmpty()) return false;
for(int i = 0; i < s.length(); i++) {
if(i == 0 && s.charAt(i) == '-') {
if(s.length() == 1) return false;
else continue;
}
if(Character.digit(s.charAt(i), radix) < 0) return false;
}
return true;
}
}
And there are two actions in the controller for create or update the TestModel, method create and method update.
public static void create(#Valid TestModel testModel){
if(validation.hasErrors()) {
params.flash();
validation.keep();
blank();
}
}
public static void update(#Valid TestModel testModel) {
if(validation.hasErrors()) {
params.flash();
validation.keep();
}
else{
testModel.save();
show(sys5000.id);
}
}
I found when the field sort is not entered with integer value, the value will be null in the create method, that's why I put a if null condition in the IntegerCheck.class.
Thus, if the value of filed sort is wrong typed, it detects null and return false.
Though it's not what I expect it will use the wrong typed value to verify, it worked...sort of.
The problem is in the update method.
For when updating an instance of TestModel, it won't show the wrong typed value, but the original retrieved value from database instead.
It's really a problem, for it will always return true if the retrieved data from database is already an integer. Then the validation won't do the work.
And the questions are:
Any advice for this validation strategy? I think maybe I'm apart from the right way to verify the Integer value validation.
How can I retrieve the wrong typed value from the action, or it's just not possible, for it's already not a valid data type of that field.
The behavior that you see in the update method is the way Play works!
Here is the relevant section from the documentation :
... When Play finds the id field, it loads the matching instance from
the database before editing it. The other parameters provided by the
HTTP request are then applied.
So in your case, when the sort property is null during an update, the value in the database is used.
Now if I were to try to achieve what you are trying to do, I would propably do it this way :
In my model
#Required
#CheckWith(IntegerCheck.class)
public int sort; // using primitive here to avoid null values.
static class IntegerCheck extends Check {
public boolean isSatisfied(Object model, Object sort) {
int fieldValue = (int) sort; // here you have the value as int
// Here you would check whatever you want and return true or false.
return ...
}
}
I am going through the Spring API. I went through the ModelAndView class. I found there two mehods in the class which return Map. One is getModel() and other is getModelInternal(). They both return Map. What is the difference between these methods.
Thank you.
Check javadoc for methods:
/**
* Return the model map. May return {#code null}.
* Called by DispatcherServlet for evaluation of the model.
*/
protected Map<String, Object> getModelInternal() {
return this.model;
}
/**
* Return the model map. Never returns {#code null}.
* To be called by application code for modifying the model.
*/
public Map<String, Object> getModel() {
return getModelMap();
}
So, one be called by client - another by framework, one nullable - another not-null.